From fe932fce6e6eb3c91c6dcac2279bb21f9fb6b885 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Fri, 21 Feb 2020 09:27:25 -0500 Subject: [PATCH 001/123] [ML] New Platform server shim: update fields service routes (#58060) * update fieldsService routes to use NP router * fix file name typo * add routes names for docs --- .../models/fields_service/fields_service.d.ts | 21 +++++ .../models/fields_service/fields_service.js | 8 +- .../fields_service/{index.js => index.ts} | 0 .../new_platform/fields_service_schema.ts | 22 +++++ .../plugins/ml/server/routes/apidoc.json | 5 +- .../ml/server/routes/fields_service.js | 49 ----------- .../ml/server/routes/fields_service.ts | 86 +++++++++++++++++++ 7 files changed, 137 insertions(+), 54 deletions(-) create mode 100644 x-pack/legacy/plugins/ml/server/models/fields_service/fields_service.d.ts rename x-pack/legacy/plugins/ml/server/models/fields_service/{index.js => index.ts} (100%) create mode 100644 x-pack/legacy/plugins/ml/server/new_platform/fields_service_schema.ts delete mode 100644 x-pack/legacy/plugins/ml/server/routes/fields_service.js create mode 100644 x-pack/legacy/plugins/ml/server/routes/fields_service.ts diff --git a/x-pack/legacy/plugins/ml/server/models/fields_service/fields_service.d.ts b/x-pack/legacy/plugins/ml/server/models/fields_service/fields_service.d.ts new file mode 100644 index 0000000000000..38f7dce93546d --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/models/fields_service/fields_service.d.ts @@ -0,0 +1,21 @@ +/* + * 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 { APICaller } from 'src/core/server'; + +export function fieldsServiceProvider( + callAsCurrentUser: APICaller +): { + getCardinalityOfFields: ( + index: string[] | string, + fieldNames: string[], + query: any, + timeFieldName: string, + earliestMs: number, + latestMs: number + ) => Promise; + getTimeFieldRange: (index: string[] | string, timeFieldName: string, query: any) => Promise; +}; diff --git a/x-pack/legacy/plugins/ml/server/models/fields_service/fields_service.js b/x-pack/legacy/plugins/ml/server/models/fields_service/fields_service.js index 3b2de50ee2e63..a538693a92aba 100644 --- a/x-pack/legacy/plugins/ml/server/models/fields_service/fields_service.js +++ b/x-pack/legacy/plugins/ml/server/models/fields_service/fields_service.js @@ -7,7 +7,7 @@ // Service for carrying out queries to obtain data // specific to fields in Elasticsearch indices. -export function fieldsServiceProvider(callWithRequest) { +export function fieldsServiceProvider(callAsCurrentUser) { // Obtains the cardinality of one or more fields. // Returns an Object whose keys are the names of the fields, // with values equal to the cardinality of the field. @@ -17,7 +17,7 @@ export function fieldsServiceProvider(callWithRequest) { // First check that each of the supplied fieldNames are aggregatable, // then obtain the cardinality for each of the aggregatable fields. return new Promise((resolve, reject) => { - callWithRequest('fieldCaps', { + callAsCurrentUser('fieldCaps', { index, fields: fieldNames, }) @@ -72,7 +72,7 @@ export function fieldsServiceProvider(callWithRequest) { aggs, }; - callWithRequest('search', { + callAsCurrentUser('search', { index, body, }) @@ -106,7 +106,7 @@ export function fieldsServiceProvider(callWithRequest) { return new Promise((resolve, reject) => { const obj = { success: true, start: { epoch: 0, string: '' }, end: { epoch: 0, string: '' } }; - callWithRequest('search', { + callAsCurrentUser('search', { index, size: 0, body: { diff --git a/x-pack/legacy/plugins/ml/server/models/fields_service/index.js b/x-pack/legacy/plugins/ml/server/models/fields_service/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/server/models/fields_service/index.js rename to x-pack/legacy/plugins/ml/server/models/fields_service/index.ts diff --git a/x-pack/legacy/plugins/ml/server/new_platform/fields_service_schema.ts b/x-pack/legacy/plugins/ml/server/new_platform/fields_service_schema.ts new file mode 100644 index 0000000000000..e0fba498e0d58 --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/new_platform/fields_service_schema.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. + */ + +import { schema } from '@kbn/config-schema'; + +export const getCardinalityOfFieldsSchema = schema.object({ + index: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]), + fieldNames: schema.maybe(schema.arrayOf(schema.string())), + query: schema.maybe(schema.any()), + timeFieldName: schema.maybe(schema.string()), + earliestMs: schema.maybe(schema.oneOf([schema.number(), schema.string()])), + latestMs: schema.maybe(schema.oneOf([schema.number(), schema.string()])), +}); + +export const getTimeFieldRangeSchema = schema.object({ + index: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]), + timeFieldName: schema.maybe(schema.string()), + query: schema.maybe(schema.any()), +}); diff --git a/x-pack/legacy/plugins/ml/server/routes/apidoc.json b/x-pack/legacy/plugins/ml/server/routes/apidoc.json index 7d1f13ead3fef..946e3bd71d6c3 100644 --- a/x-pack/legacy/plugins/ml/server/routes/apidoc.json +++ b/x-pack/legacy/plugins/ml/server/routes/apidoc.json @@ -105,6 +105,9 @@ "DeleteDatafeed", "StartDatafeed", "StopDatafeed", - "PreviewDatafeed" + "PreviewDatafeed", + "FieldsService", + "GetCardinalityOfFields", + "GetTimeFieldRange" ] } diff --git a/x-pack/legacy/plugins/ml/server/routes/fields_service.js b/x-pack/legacy/plugins/ml/server/routes/fields_service.js deleted file mode 100644 index 7848ffbd8bafe..0000000000000 --- a/x-pack/legacy/plugins/ml/server/routes/fields_service.js +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { callWithRequestFactory } from '../client/call_with_request_factory'; -import { wrapError } from '../client/errors'; -import { fieldsServiceProvider } from '../models/fields_service'; - -function getCardinalityOfFields(callWithRequest, payload) { - const fs = fieldsServiceProvider(callWithRequest); - const { index, fieldNames, query, timeFieldName, earliestMs, latestMs } = payload; - return fs.getCardinalityOfFields(index, fieldNames, query, timeFieldName, earliestMs, latestMs); -} - -function getTimeFieldRange(callWithRequest, payload) { - const fs = fieldsServiceProvider(callWithRequest); - const { index, timeFieldName, query } = payload; - return fs.getTimeFieldRange(index, timeFieldName, query); -} - -export function fieldsService({ commonRouteConfig, elasticsearchPlugin, route }) { - route({ - method: 'POST', - path: '/api/ml/fields_service/field_cardinality', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return getCardinalityOfFields(callWithRequest, request.payload).catch(resp => - wrapError(resp) - ); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'POST', - path: '/api/ml/fields_service/time_field_range', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return getTimeFieldRange(callWithRequest, request.payload).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); -} diff --git a/x-pack/legacy/plugins/ml/server/routes/fields_service.ts b/x-pack/legacy/plugins/ml/server/routes/fields_service.ts new file mode 100644 index 0000000000000..4827adf23d7b4 --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/routes/fields_service.ts @@ -0,0 +1,86 @@ +/* + * 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 { RequestHandlerContext } from 'src/core/server'; +import { licensePreRoutingFactory } from '../new_platform/licence_check_pre_routing_factory'; +import { wrapError } from '../client/error_wrapper'; +import { RouteInitialization } from '../new_platform/plugin'; +import { + getCardinalityOfFieldsSchema, + getTimeFieldRangeSchema, +} from '../new_platform/fields_service_schema'; +import { fieldsServiceProvider } from '../models/fields_service'; + +function getCardinalityOfFields(context: RequestHandlerContext, payload: any) { + const fs = fieldsServiceProvider(context.ml!.mlClient.callAsCurrentUser); + const { index, fieldNames, query, timeFieldName, earliestMs, latestMs } = payload; + return fs.getCardinalityOfFields(index, fieldNames, query, timeFieldName, earliestMs, latestMs); +} + +function getTimeFieldRange(context: RequestHandlerContext, payload: any) { + const fs = fieldsServiceProvider(context.ml!.mlClient.callAsCurrentUser); + const { index, timeFieldName, query } = payload; + return fs.getTimeFieldRange(index, timeFieldName, query); +} + +/** + * Routes for fields service + */ +export function fieldsService({ xpackMainPlugin, router }: RouteInitialization) { + /** + * @apiGroup FieldsService + * + * @api {post} /api/ml/fields_service/field_cardinality Get cardinality of fields + * @apiName GetCardinalityOfFields + * @apiDescription Returns the cardinality of one or more fields. Returns an Object whose keys are the names of the fields, with values equal to the cardinality of the field + */ + router.post( + { + path: '/api/ml/fields_service/field_cardinality', + validate: { + body: getCardinalityOfFieldsSchema, + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const resp = await getCardinalityOfFields(context, request.body); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup FieldsService + * + * @api {post} /api/ml/fields_service/time_field_range Get time field range + * @apiName GetTimeFieldRange + * @apiDescription Returns the timefield range for the given index + */ + router.post( + { + path: '/api/ml/fields_service/time_field_range', + validate: { + body: getTimeFieldRangeSchema, + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const resp = await getTimeFieldRange(context, request.body); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); +} From 96000fa425932618211b76643ef6914335beb28e Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 21 Feb 2020 15:31:57 +0100 Subject: [PATCH 002/123] [ML] Transforms: Adds clone feature to transforms list. (#57837) Adds a Clone action to the transform management list. The action opens the transform wizard with prepopulated configurations based on the selected transform. The fields for the transform name and target index will not be populated to avoid the obvious "already exists" warnings. --- .../plugins/transform/public/app/app.tsx | 5 + .../transform/public/app/common/index.ts | 3 + .../public/app/common/request.test.ts | 11 +- .../transform/public/app/common/request.ts | 6 + .../transform/public/app/constants/index.ts | 1 + .../transform/public/app/lib/kibana/common.ts | 34 ++- .../transform/public/app/lib/kibana/index.ts | 1 + .../public/app/lib/kibana/kibana_context.tsx | 18 +- .../public/app/lib/kibana/kibana_provider.tsx | 20 +- .../clone_transform_section.tsx | 194 ++++++++++++++++++ .../app/sections/clone_transform/index.ts | 7 + .../use_source_index_data.ts | 3 +- .../components/step_define/index.ts | 3 +- .../step_define/step_define_form.tsx | 72 ++++++- .../components/step_details/index.ts | 6 +- .../step_details/step_details_form.tsx | 16 ++ .../components/wizard/wizard.tsx | 26 ++- .../transform_list/action_clone.tsx | 60 ++++++ .../transform_list/actions.test.tsx | 3 +- .../components/transform_list/actions.tsx | 6 + .../app/services/navigation/breadcrumb.ts | 8 + .../public/app/services/text/text.ts | 3 + 22 files changed, 454 insertions(+), 52 deletions(-) create mode 100644 x-pack/legacy/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx create mode 100644 x-pack/legacy/plugins/transform/public/app/sections/clone_transform/index.ts create mode 100644 x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_clone.tsx diff --git a/x-pack/legacy/plugins/transform/public/app/app.tsx b/x-pack/legacy/plugins/transform/public/app/app.tsx index 825c1761bf619..0f21afbcccca8 100644 --- a/x-pack/legacy/plugins/transform/public/app/app.tsx +++ b/x-pack/legacy/plugins/transform/public/app/app.tsx @@ -16,6 +16,7 @@ import { getAppProviders } from './app_dependencies'; import { AuthorizationContext } from './lib/authorization'; import { AppDependencies } from '../shim'; +import { CloneTransformSection } from './sections/clone_transform'; import { CreateTransformSection } from './sections/create_transform'; import { TransformManagementSection } from './sections/transform_management'; @@ -39,6 +40,10 @@ export const App: FC = () => { return (
+ { + test('isMatchAllQuery()', () => { + expect(isMatchAllQuery(defaultQuery)).toBe(false); + expect(isMatchAllQuery(matchAllQuery)).toBe(true); + expect(isMatchAllQuery(simpleQuery)).toBe(false); + }); + test('isSimpleQuery()', () => { expect(isSimpleQuery(defaultQuery)).toBe(true); expect(isSimpleQuery(matchAllQuery)).toBe(false); diff --git a/x-pack/legacy/plugins/transform/public/app/common/request.ts b/x-pack/legacy/plugins/transform/public/app/common/request.ts index 5d508f3d245d3..3b740de177ef8 100644 --- a/x-pack/legacy/plugins/transform/public/app/common/request.ts +++ b/x-pack/legacy/plugins/transform/public/app/common/request.ts @@ -53,6 +53,12 @@ export function isSimpleQuery(arg: any): arg is SimpleQuery { return arg.query_string !== undefined; } +export const matchAllQuery = { match_all: {} }; +export function isMatchAllQuery(query: any): boolean { + return query.match_all !== undefined && Object.keys(query.match_all).length === 0; +} + +export const defaultQuery: PivotQuery = { query_string: { query: '*' } }; export function isDefaultQuery(query: PivotQuery): boolean { return isSimpleQuery(query) && query.query_string.query === '*'; } diff --git a/x-pack/legacy/plugins/transform/public/app/constants/index.ts b/x-pack/legacy/plugins/transform/public/app/constants/index.ts index 85ffc222f59a2..78b5f018dd782 100644 --- a/x-pack/legacy/plugins/transform/public/app/constants/index.ts +++ b/x-pack/legacy/plugins/transform/public/app/constants/index.ts @@ -8,6 +8,7 @@ export const CLIENT_BASE_PATH = '/management/elasticsearch/transform'; export enum SECTION_SLUG { HOME = 'transform_management', + CLONE_TRANSFORM = 'clone_transform', CREATE_TRANSFORM = 'create_transform', } diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts b/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts index 3e55d509a94ab..aba61766b5d2b 100644 --- a/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts @@ -4,17 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObjectsClientContract, IUiSettingsClient } from 'src/core/public'; +import { SavedObjectsClientContract, SimpleSavedObject, IUiSettingsClient } from 'src/core/public'; import { IndexPattern, esQuery, IndexPatternsContract, } from '../../../../../../../../src/plugins/data/public'; +import { matchAllQuery } from '../../common'; + type IndexPatternId = string; type SavedSearchId = string; -let indexPatternCache = []; +let indexPatternCache: Array>> = []; let fullIndexPatterns; let currentIndexPattern = null; let currentSavedSearch = null; @@ -53,6 +55,10 @@ export function loadIndexPatterns( }); } +export function getIndexPatternIdByTitle(indexPatternTitle: string): string | undefined { + return indexPatternCache.find(d => d?.attributes?.title === indexPatternTitle)?.id; +} + type CombinedQuery = Record<'bool', any> | unknown; export function loadCurrentIndexPattern( @@ -69,12 +75,20 @@ export function loadCurrentSavedSearch(savedSearches: any, savedSearchId: SavedS return currentSavedSearch; } +function isIndexPattern(arg: any): arg is IndexPattern { + return arg !== undefined; +} // Helper for creating the items used for searching and job creation. export function createSearchItems( indexPattern: IndexPattern | undefined, savedSearch: any, config: IUiSettingsClient -) { +): { + indexPattern: IndexPattern; + savedSearch: any; + query: any; + combinedQuery: CombinedQuery; +} { // query is only used by the data visualizer as it needs // a lucene query_string. // Using a blank query will cause match_all:{} to be used @@ -86,17 +100,13 @@ export function createSearchItems( let combinedQuery: CombinedQuery = { bool: { - must: [ - { - match_all: {}, - }, - ], + must: [matchAllQuery], }, }; - if (indexPattern === undefined && savedSearch !== null && savedSearch.id !== undefined) { + if (!isIndexPattern(indexPattern) && savedSearch !== null && savedSearch.id !== undefined) { const searchSource = savedSearch.searchSource; - indexPattern = searchSource.getField('index'); + indexPattern = searchSource.getField('index') as IndexPattern; query = searchSource.getField('query'); const fs = searchSource.getField('filter'); @@ -107,6 +117,10 @@ export function createSearchItems( combinedQuery = esQuery.buildEsQuery(indexPattern, [query], filters, esQueryConfigs); } + if (!isIndexPattern(indexPattern)) { + throw new Error('Index Pattern is not defined.'); + } + return { indexPattern, savedSearch, diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/index.ts b/x-pack/legacy/plugins/transform/public/app/lib/kibana/index.ts index 82d5362e21c02..62107cb37ff2c 100644 --- a/x-pack/legacy/plugins/transform/public/app/lib/kibana/index.ts +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/index.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +export { getIndexPatternIdByTitle, loadIndexPatterns } from './common'; export { useKibanaContext, InitializedKibanaContextValue, diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_context.tsx b/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_context.tsx index 5b7702a0193ec..b0a0371d2de86 100644 --- a/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_context.tsx +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_context.tsx @@ -6,30 +6,26 @@ import React, { createContext, useContext, FC } from 'react'; +import { IUiSettingsClient } from 'kibana/public'; + import { SavedSearch } from '../../../../../../../../src/legacy/core_plugins/kibana/public/discover/np_ready/types'; import { IndexPattern, IndexPatternsContract, } from '../../../../../../../../src/plugins/data/public'; -import { KibanaConfig } from '../../../../../../../../src/legacy/server/kbn_server'; - -// set() method is missing in original d.ts -interface KibanaConfigTypeFix extends KibanaConfig { - set(key: string, value: any): void; -} interface UninitializedKibanaContextValue { - initialized: boolean; + initialized: false; } export interface InitializedKibanaContextValue { combinedQuery: any; - currentIndexPattern: IndexPattern; - currentSavedSearch: SavedSearch; indexPatterns: IndexPatternsContract; - initialized: boolean; + initialized: true; kbnBaseUrl: string; - kibanaConfig: KibanaConfigTypeFix; + kibanaConfig: IUiSettingsClient; + currentIndexPattern: IndexPattern; + currentSavedSearch?: SavedSearch; } export type KibanaContextValue = UninitializedKibanaContextValue | InitializedKibanaContextValue; diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_provider.tsx b/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_provider.tsx index 0a9de49168ad4..d2cf5f2b32910 100644 --- a/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_provider.tsx +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_provider.tsx @@ -17,7 +17,7 @@ import { loadCurrentSavedSearch, } from './common'; -import { KibanaContext, KibanaContextValue } from './kibana_context'; +import { InitializedKibanaContextValue, KibanaContext, KibanaContextValue } from './kibana_context'; const indexPatterns = npStart.plugins.data.indexPatterns; const savedObjectsClient = npStart.core.savedObjects.client; @@ -52,20 +52,20 @@ export const KibanaProvider: FC = ({ savedObjectId, children }) => { const kibanaConfig = npStart.core.uiSettings; - const { indexPattern, savedSearch, combinedQuery } = createSearchItems( - fetchedIndexPattern, - fetchedSavedSearch, - kibanaConfig - ); - - const kibanaContext = { + const { + indexPattern: currentIndexPattern, + savedSearch: currentSavedSearch, combinedQuery, - currentIndexPattern: indexPattern, - currentSavedSearch: savedSearch, + } = createSearchItems(fetchedIndexPattern, fetchedSavedSearch, kibanaConfig); + + const kibanaContext: InitializedKibanaContextValue = { indexPatterns, initialized: true, kbnBaseUrl: npStart.core.injectedMetadata.getBasePath(), kibanaConfig, + combinedQuery, + currentIndexPattern, + currentSavedSearch, }; setContextValue(kibanaContext); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx b/x-pack/legacy/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx new file mode 100644 index 0000000000000..de96a4de32962 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx @@ -0,0 +1,194 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useEffect, useState, FC } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; + +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; + +import { + EuiBetaBadge, + EuiButtonEmpty, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiPageContent, + EuiPageContentBody, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; + +import { npStart } from 'ui/new_platform'; + +import { useApi } from '../../hooks/use_api'; + +import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; +import { TransformPivotConfig } from '../../common'; +import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../services/navigation'; +import { documentationLinksService } from '../../services/documentation'; +import { PrivilegesWrapper } from '../../lib/authorization'; +import { + getIndexPatternIdByTitle, + loadIndexPatterns, + KibanaProvider, + RenderOnlyWithInitializedKibanaContext, +} from '../../lib/kibana'; + +import { Wizard } from '../create_transform/components/wizard'; + +const indexPatterns = npStart.plugins.data.indexPatterns; +const savedObjectsClient = npStart.core.savedObjects.client; + +interface GetTransformsResponseOk { + count: number; + transforms: TransformPivotConfig[]; +} + +interface GetTransformsResponseError { + error: { + msg: string; + path: string; + query: any; + statusCode: number; + response: string; + }; +} + +function isGetTransformsResponseError(arg: any): arg is GetTransformsResponseError { + return arg.error !== undefined; +} + +type GetTransformsResponse = GetTransformsResponseOk | GetTransformsResponseError; + +type Props = RouteComponentProps<{ transformId: string }>; +export const CloneTransformSection: FC = ({ match }) => { + // Set breadcrumb and page title + useEffect(() => { + breadcrumbService.setBreadcrumbs(BREADCRUMB_SECTION.CLONE_TRANSFORM); + docTitleService.setTitle('createTransform'); + }, []); + + const api = useApi(); + + const transformId = match.params.transformId; + + const [transformConfig, setTransformConfig] = useState(); + const [errorMessage, setErrorMessage] = useState(); + const [isInitialized, setIsInitialized] = useState(false); + const [savedObjectId, setSavedObjectId] = useState(undefined); + + const fetchTransformConfig = async () => { + try { + const transformConfigs: GetTransformsResponse = await api.getTransforms(transformId); + if (isGetTransformsResponseError(transformConfigs)) { + setTransformConfig(undefined); + setErrorMessage(transformConfigs.error.msg); + setIsInitialized(true); + return; + } + + await loadIndexPatterns(savedObjectsClient, indexPatterns); + const indexPatternTitle = Array.isArray(transformConfigs.transforms[0].source.index) + ? transformConfigs.transforms[0].source.index.join(',') + : transformConfigs.transforms[0].source.index; + const indexPatternId = getIndexPatternIdByTitle(indexPatternTitle); + + if (indexPatternId === undefined) { + throw new Error( + i18n.translate('xpack.transform.clone.errorPromptText', { + defaultMessage: 'Could not fetch the Kibana index pattern ID.', + }) + ); + } + + setSavedObjectId(indexPatternId); + + setTransformConfig(transformConfigs.transforms[0]); + setErrorMessage(undefined); + setIsInitialized(true); + } catch (e) { + setTransformConfig(undefined); + if (e.message !== undefined) { + setErrorMessage(e.message); + } else { + setErrorMessage(JSON.stringify(e, null, 2)); + } + setIsInitialized(true); + } + }; + + useEffect(() => { + fetchTransformConfig(); + // The effect should only be called once. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + + + + +

+ +   + +

+
+ + + + + +
+
+ + + {typeof errorMessage !== 'undefined' && ( + +
{JSON.stringify(errorMessage)}
+
+ )} + {savedObjectId !== undefined && isInitialized === true && transformConfig !== undefined && ( + + + + + + )} +
+
+
+ ); +}; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/clone_transform/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/clone_transform/index.ts new file mode 100644 index 0000000000000..fef33d50130a7 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/clone_transform/index.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 { CloneTransformSection } from './clone_transform_section'; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/use_source_index_data.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/use_source_index_data.ts index 3fcc3cc15803b..e5c6783db1022 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/use_source_index_data.ts +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/use_source_index_data.ts @@ -17,6 +17,7 @@ import { getDefaultSelectableFields, getFlattenedFields, isDefaultQuery, + matchAllQuery, EsDoc, EsDocSource, EsFieldName, @@ -75,7 +76,7 @@ export const useSourceIndexData = ( index: indexPattern.title, size: SEARCH_SIZE, // Instead of using the default query (`*`), fall back to a more efficient `match_all` query. - body: { query: isDefaultQuery(query) ? { match_all: {} } : query }, + body: { query: isDefaultQuery(query) ? matchAllQuery : query }, }); if (isErrorResponse(resp)) { diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/index.ts index 7c5b60715961b..881e8c6b26658 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/index.ts +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/index.ts @@ -5,8 +5,9 @@ */ export { + applyTransformConfigToDefineState, + getDefaultStepDefineState, StepDefineExposedState, StepDefineForm, - getDefaultStepDefineState, } from './step_define_form'; export { StepDefineSummary } from './step_define_summary'; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx index b8f63ef697e78..675386be8e2a5 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { isEqual } from 'lodash'; import React, { Fragment, FC, useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; @@ -27,7 +28,8 @@ import { EuiSwitch, } from '@elastic/eui'; -import { dictionaryToArray } from '../../../../../../common/types/common'; +import { TransformPivotConfig } from '../../../../common'; +import { dictionaryToArray, Dictionary } from '../../../../../../common/types/common'; import { DropDown } from '../aggregation_dropdown'; import { AggListForm } from '../aggregation_list'; import { GroupByListForm } from '../group_by_list'; @@ -43,10 +45,12 @@ import { } from '../../../../lib/kibana'; import { - AggName, - DropDownLabel, getPivotQuery, getPreviewRequestBody, + isMatchAllQuery, + matchAllQuery, + AggName, + DropDownLabel, PivotAggDict, PivotAggsConfig, PivotAggsConfigDict, @@ -55,6 +59,7 @@ import { PivotGroupByConfigDict, PivotSupportedGroupByAggs, PIVOT_SUPPORTED_AGGS, + PIVOT_SUPPORTED_GROUP_BY_AGGS, } from '../../../../common'; import { getPivotDropdownOptions } from './common'; @@ -89,6 +94,58 @@ export function getDefaultStepDefineState( valid: false, }; } + +export function applyTransformConfigToDefineState( + state: StepDefineExposedState, + transformConfig?: TransformPivotConfig +): StepDefineExposedState { + // apply the transform configuration to wizard DEFINE state + if (transformConfig !== undefined) { + // transform aggregations config to wizard state + state.aggList = Object.keys(transformConfig.pivot.aggregations).reduce((aggList, aggName) => { + const aggConfig = transformConfig.pivot.aggregations[aggName] as Dictionary; + const agg = Object.keys(aggConfig)[0]; + aggList[aggName] = { + ...aggConfig[agg], + agg: agg as PIVOT_SUPPORTED_AGGS, + aggName, + dropDownName: aggName, + } as PivotAggsConfig; + return aggList; + }, {} as PivotAggsConfigDict); + + // transform group by config to wizard state + state.groupByList = Object.keys(transformConfig.pivot.group_by).reduce( + (groupByList, groupByName) => { + const groupByConfig = transformConfig.pivot.group_by[groupByName] as Dictionary; + const groupBy = Object.keys(groupByConfig)[0]; + groupByList[groupByName] = { + agg: groupBy as PIVOT_SUPPORTED_GROUP_BY_AGGS, + aggName: groupByName, + dropDownName: groupByName, + ...groupByConfig[groupBy], + } as PivotGroupByConfig; + return groupByList; + }, + {} as PivotGroupByConfigDict + ); + + // only apply the query from the transform config to wizard state if it's not the default query + const query = transformConfig.source.query; + if (query !== undefined && !isEqual(query, matchAllQuery)) { + state.isAdvancedSourceEditorEnabled = true; + state.searchString = ''; + state.searchQuery = query; + state.sourceConfigUpdated = true; + } + + // applying a transform config to wizard state will always result in a valid configuration + state.valid = true; + } + + return state; +} + export function isAggNameConflict( aggName: AggName, aggList: PivotAggsConfigDict, @@ -208,10 +265,7 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange const searchHandler = (d: Record) => { const { filterQuery, queryString } = d; const newSearch = queryString === emptySearch ? defaultSearch : queryString; - const newSearchQuery = - filterQuery.match_all && Object.keys(filterQuery.match_all).length === 0 - ? defaultSearch - : filterQuery; + const newSearchQuery = isMatchAllQuery(filterQuery) ? defaultSearch : filterQuery; setSearchString(newSearch); setSearchQuery(newSearchQuery); }; @@ -363,10 +417,10 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange const aggConfigKeys = Object.keys(aggConfig); const agg = aggConfigKeys[0] as PivotSupportedGroupByAggs; newGroupByList[aggName] = { + ...aggConfig[agg], agg, aggName, dropDownName: '', - ...aggConfig[agg], }; }); } @@ -380,10 +434,10 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange const aggConfigKeys = Object.keys(aggConfig); const agg = aggConfigKeys[0] as PIVOT_SUPPORTED_AGGS; newAggList[aggName] = { + ...aggConfig[agg], agg, aggName, dropDownName: '', - ...aggConfig[agg], }; }); } diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/index.ts index e454ea32d76ed..5cbdf4500e3c3 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/index.ts +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/index.ts @@ -4,5 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -export { StepDetailsForm, getDefaultStepDetailsState } from './step_details_form'; +export { + applyTransformConfigToDetailsState, + getDefaultStepDetailsState, + StepDetailsForm, +} from './step_details_form'; export { StepDetailsSummary } from './step_details_summary'; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index a01481fde343c..220923f88ed36 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -49,6 +49,22 @@ export function getDefaultStepDetailsState(): StepDetailsExposedState { }; } +export function applyTransformConfigToDetailsState( + state: StepDetailsExposedState, + transformConfig?: TransformPivotConfig +): StepDetailsExposedState { + // apply the transform configuration to wizard DETAILS state + if (transformConfig !== undefined) { + const time = transformConfig.sync?.time; + if (time !== undefined) { + state.continuousModeDateField = time.field; + state.continuousModeDelay = time.delay; + state.isContinuousModeEnabled = true; + } + } + return state; +} + interface Props { overrides?: StepDetailsExposedState; onChange(s: StepDetailsExposedState): void; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard/wizard.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard/wizard.tsx index 109cf81da6caa..f1861755d9742 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard/wizard.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard/wizard.tsx @@ -12,16 +12,22 @@ import { EuiSteps, EuiStepStatus } from '@elastic/eui'; import { useKibanaContext } from '../../../../lib/kibana'; -import { getCreateRequestBody } from '../../../../common'; +import { getCreateRequestBody, TransformPivotConfig } from '../../../../common'; import { + applyTransformConfigToDefineState, + getDefaultStepDefineState, StepDefineExposedState, StepDefineForm, StepDefineSummary, - getDefaultStepDefineState, } from '../step_define'; import { getDefaultStepCreateState, StepCreateForm, StepCreateSummary } from '../step_create'; -import { getDefaultStepDetailsState, StepDetailsForm, StepDetailsSummary } from '../step_details'; +import { + applyTransformConfigToDetailsState, + getDefaultStepDetailsState, + StepDetailsForm, + StepDetailsSummary, +} from '../step_details'; import { WizardNav } from '../wizard_nav'; enum KBN_MANAGEMENT_PAGE_CLASSNAME { @@ -67,17 +73,25 @@ const StepDefine: FC = ({ ); }; -export const Wizard: FC = React.memo(() => { +interface WizardProps { + cloneConfig?: TransformPivotConfig; +} + +export const Wizard: FC = React.memo(({ cloneConfig }) => { const kibanaContext = useKibanaContext(); // The current WIZARD_STEP const [currentStep, setCurrentStep] = useState(WIZARD_STEPS.DEFINE); // The DEFINE state - const [stepDefineState, setStepDefineState] = useState(getDefaultStepDefineState(kibanaContext)); + const [stepDefineState, setStepDefineState] = useState( + applyTransformConfigToDefineState(getDefaultStepDefineState(kibanaContext), cloneConfig) + ); // The DETAILS state - const [stepDetailsState, setStepDetailsState] = useState(getDefaultStepDetailsState()); + const [stepDetailsState, setStepDetailsState] = useState( + applyTransformConfigToDetailsState(getDefaultStepDetailsState(), cloneConfig) + ); const stepDetails = currentStep === WIZARD_STEPS.DETAILS ? ( diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_clone.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_clone.tsx new file mode 100644 index 0000000000000..40098ac7ef72a --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_clone.tsx @@ -0,0 +1,60 @@ +/* + * 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, { FC, useContext } from 'react'; +import { useHistory } from 'react-router-dom'; +import { i18n } from '@kbn/i18n'; +import { EuiButtonEmpty, EuiToolTip } from '@elastic/eui'; + +import { + createCapabilityFailureMessage, + AuthorizationContext, +} from '../../../../lib/authorization'; + +import { CLIENT_BASE_PATH, SECTION_SLUG } from '../../../../constants'; + +interface CloneActionProps { + itemId: string; +} + +export const CloneAction: FC = ({ itemId }) => { + const history = useHistory(); + + const { canCreateTransform } = useContext(AuthorizationContext).capabilities; + + const buttonCloneText = i18n.translate('xpack.transform.transformList.cloneActionName', { + defaultMessage: 'Clone', + }); + + function clickHandler() { + history.push(`${CLIENT_BASE_PATH}/${SECTION_SLUG.CLONE_TRANSFORM}/${itemId}`); + } + + const cloneButton = ( + + {buttonCloneText} + + ); + + if (!canCreateTransform) { + const content = createCapabilityFailureMessage('canStartStopTransform'); + + return ( + + {cloneButton} + + ); + } + + return <>{cloneButton}; +}; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.test.tsx index 3d847890b2bd5..ef92a5e3859d7 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.test.tsx @@ -12,9 +12,10 @@ describe('Transform: Transform List Actions', () => { test('getActions()', () => { const actions = getActions({ forceDisable: false }); - expect(actions).toHaveLength(2); + expect(actions).toHaveLength(3); expect(actions[0].isPrimary).toBeTruthy(); expect(typeof actions[0].render).toBe('function'); expect(typeof actions[1].render).toBe('function'); + expect(typeof actions[2].render).toBe('function'); }); }); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.tsx index 1773405e36e39..3e3829973e328 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.tsx @@ -6,6 +6,7 @@ import React from 'react'; import { TransformListRow, TRANSFORM_STATE } from '../../../../common'; +import { CloneAction } from './action_clone'; import { StartAction } from './action_start'; import { StopAction } from './action_stop'; import { DeleteAction } from './action_delete'; @@ -21,6 +22,11 @@ export const getActions = ({ forceDisable }: { forceDisable: boolean }) => { return ; }, }, + { + render: (item: TransformListRow) => { + return ; + }, + }, { render: (item: TransformListRow) => { return ; diff --git a/x-pack/legacy/plugins/transform/public/app/services/navigation/breadcrumb.ts b/x-pack/legacy/plugins/transform/public/app/services/navigation/breadcrumb.ts index 0e0b174f28f99..5a2f698b35154 100644 --- a/x-pack/legacy/plugins/transform/public/app/services/navigation/breadcrumb.ts +++ b/x-pack/legacy/plugins/transform/public/app/services/navigation/breadcrumb.ts @@ -10,6 +10,7 @@ import { linkToHome } from './links'; export enum BREADCRUMB_SECTION { MANAGEMENT = 'management', HOME = 'home', + CLONE_TRANSFORM = 'cloneTransform', CREATE_TRANSFORM = 'createTransform', } @@ -27,6 +28,7 @@ class BreadcrumbService { private breadcrumbs: Breadcrumbs = { management: [], home: [], + cloneTransform: [], createTransform: [], }; @@ -42,6 +44,12 @@ class BreadcrumbService { href: linkToHome(), }, ]; + this.breadcrumbs.cloneTransform = [ + ...this.breadcrumbs.home, + { + text: textService.breadcrumbs.cloneTransform, + }, + ]; this.breadcrumbs.createTransform = [ ...this.breadcrumbs.home, { diff --git a/x-pack/legacy/plugins/transform/public/app/services/text/text.ts b/x-pack/legacy/plugins/transform/public/app/services/text/text.ts index df1b07e171c62..af4aea7e8db4e 100644 --- a/x-pack/legacy/plugins/transform/public/app/services/text/text.ts +++ b/x-pack/legacy/plugins/transform/public/app/services/text/text.ts @@ -14,6 +14,9 @@ class TextService { home: i18n.translate('xpack.transform.home.breadcrumbTitle', { defaultMessage: 'Transforms', }), + cloneTransform: i18n.translate('xpack.transform.cloneTransform.breadcrumbTitle', { + defaultMessage: 'Clone transform', + }), createTransform: i18n.translate('xpack.transform.createTransform.breadcrumbTitle', { defaultMessage: 'Create transform', }), From 68e79e45a5f49d749ea6d0ef1f039b914cbc6bf9 Mon Sep 17 00:00:00 2001 From: Vadim Dalecky Date: Fri, 21 Feb 2020 15:35:20 +0100 Subject: [PATCH 003/123] Trigger context (#57870) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 annotate with comments Trigger and add createContext( * feat: 🎸 add TriggerContext type * feat: 🎸 improve trigger setup in embeddable plugin * feat: 🎸 export trigger vars and types from embeddable * feat: 🎸 add internal representation of Trigger * feat: 🎸 use new trigger interface to execute in vis embeddable * feat: 🎸 add TriggerContextMapping interface * feat: 🎸 improve trigger types * refactor: 💡 remove trigger ID getter * chore: 🤖 remove commented out line * chore: 🤖 re-export more trigger stuff * refactor: 💡 simplify Trigger interface * suggestions * Remove unused type Co-authored-by: Stacey Gammon --- .../public/embeddable/visualize_embeddable.ts | 14 ++-- src/plugins/embeddable/public/bootstrap.ts | 71 ++++++++--------- src/plugins/embeddable/public/index.ts | 26 ++++--- .../embeddable/public/lib/triggers/index.ts | 6 +- .../public/lib/triggers/triggers.ts | 65 ++++++++++++++++ src/plugins/ui_actions/public/index.ts | 3 +- .../public/service/ui_actions_service.test.ts | 5 +- .../public/service/ui_actions_service.ts | 65 ++++++---------- .../ui_actions/public/triggers/index.ts | 4 +- .../ui_actions/public/triggers/trigger.ts | 31 +++++++- .../public/triggers/trigger_contract.ts | 56 ++++++++++++++ .../public/triggers/trigger_internal.ts | 76 +++++++++++++++++++ src/plugins/ui_actions/public/types.ts | 10 ++- 13 files changed, 321 insertions(+), 111 deletions(-) create mode 100644 src/plugins/embeddable/public/lib/triggers/triggers.ts create mode 100644 src/plugins/ui_actions/public/triggers/trigger_contract.ts create mode 100644 src/plugins/ui_actions/public/triggers/trigger_internal.ts diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts index 4c6c12f825609..72a0ef72b5693 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -24,6 +24,7 @@ import * as Rx from 'rxjs'; import { buildPipeline } from 'ui/visualize/loader/pipeline_helpers'; import { npStart } from 'ui/new_platform'; import { IExpressionLoaderParams } from 'src/plugins/expressions/public'; +import { EmbeddableVisTriggerContext } from 'src/plugins/embeddable/public'; import { VISUALIZE_EMBEDDABLE_TYPE } from './constants'; import { IIndexPattern, @@ -39,8 +40,8 @@ import { EmbeddableOutput, Embeddable, Container, - VALUE_CLICK_TRIGGER, - SELECT_RANGE_TRIGGER, + selectRangeTrigger, + valueClickTrigger, } from '../../../../../plugins/embeddable/public'; import { dispatchRenderComplete } from '../../../../../plugins/kibana_utils/public'; import { SavedObject } from '../../../../../plugins/saved_objects/public'; @@ -301,13 +302,14 @@ export class VisualizeEmbeddable extends Embeddable { - const triggerContext: Trigger = { - id: CONTEXT_MENU_TRIGGER, - title: 'Context menu', - description: 'Triggered on top-right corner context-menu select.', - }; - const triggerFilter: Trigger = { - id: APPLY_FILTER_TRIGGER, - title: 'Filter click', - description: 'Triggered when user applies filter to an embeddable.', - }; - const triggerBadge: Trigger = { - id: PANEL_BADGE_TRIGGER, - title: 'Panel badges', - description: 'Actions appear in title bar when an embeddable loads in a panel', - }; - const selectRangeTrigger: Trigger = { - id: SELECT_RANGE_TRIGGER, - title: 'Select range', - description: 'Applies a range filter', - }; - const valueClickTrigger: Trigger = { - id: VALUE_CLICK_TRIGGER, - title: 'Value clicked', - description: 'Value was clicked', - }; + uiActions.registerTrigger(contextMenuTrigger); + uiActions.registerTrigger(applyFilterTrigger); + uiActions.registerTrigger(panelBadgeTrigger); + uiActions.registerTrigger(selectRangeTrigger); + uiActions.registerTrigger(valueClickTrigger); + const actionApplyFilter = createFilterAction(); - uiActions.registerTrigger(triggerContext); - uiActions.registerTrigger(triggerFilter); uiActions.registerAction(actionApplyFilter); - uiActions.registerTrigger(triggerBadge); - uiActions.registerTrigger(selectRangeTrigger); - uiActions.registerTrigger(valueClickTrigger); - // uiActions.attachAction(triggerFilter.id, actionApplyFilter.id); }; diff --git a/src/plugins/embeddable/public/index.ts b/src/plugins/embeddable/public/index.ts index b0e14a04a9944..2eafe16442e18 100644 --- a/src/plugins/embeddable/public/index.ts +++ b/src/plugins/embeddable/public/index.ts @@ -23,18 +23,17 @@ import { PluginInitializerContext } from 'src/core/public'; import { EmbeddablePublicPlugin } from './plugin'; export { + Adapters, ADD_PANEL_ACTION_ID, + AddPanelAction, APPLY_FILTER_ACTION, APPLY_FILTER_TRIGGER, - PANEL_BADGE_TRIGGER, - SELECT_RANGE_TRIGGER, - VALUE_CLICK_TRIGGER, - Adapters, - AddPanelAction, - CONTEXT_MENU_TRIGGER, + applyFilterTrigger, Container, ContainerInput, ContainerOutput, + CONTEXT_MENU_TRIGGER, + contextMenuTrigger, EDIT_PANEL_ACTION_ID, EditPanelAction, Embeddable, @@ -42,25 +41,32 @@ export { EmbeddableChildPanelProps, EmbeddableFactory, EmbeddableFactoryNotFoundError, + EmbeddableFactoryRenderer, EmbeddableInput, EmbeddableInstanceConfiguration, EmbeddableOutput, EmbeddablePanel, + EmbeddableRoot, + EmbeddableVisTriggerContext, ErrorEmbeddable, GetEmbeddableFactories, GetEmbeddableFactory, IContainer, IEmbeddable, + isErrorEmbeddable, + openAddPanelFlyout, OutputSpec, + PANEL_BADGE_TRIGGER, + panelBadgeTrigger, PanelNotFoundError, PanelState, PropertySpec, + SELECT_RANGE_TRIGGER, + selectRangeTrigger, + VALUE_CLICK_TRIGGER, + valueClickTrigger, ViewMode, - isErrorEmbeddable, - openAddPanelFlyout, withEmbeddableSubscription, - EmbeddableFactoryRenderer, - EmbeddableRoot, } from './lib'; export function plugin(initializerContext: PluginInitializerContext) { diff --git a/src/plugins/embeddable/public/lib/triggers/index.ts b/src/plugins/embeddable/public/lib/triggers/index.ts index 72565b3f527ad..4f981562a49ba 100644 --- a/src/plugins/embeddable/public/lib/triggers/index.ts +++ b/src/plugins/embeddable/public/lib/triggers/index.ts @@ -17,8 +17,4 @@ * under the License. */ -export const CONTEXT_MENU_TRIGGER = 'CONTEXT_MENU_TRIGGER'; -export const APPLY_FILTER_TRIGGER = 'FILTER_TRIGGER'; -export const SELECT_RANGE_TRIGGER = 'SELECT_RANGE_TRIGGER'; -export const VALUE_CLICK_TRIGGER = 'VALUE_CLICK_TRIGGER'; -export const PANEL_BADGE_TRIGGER = 'PANEL_BADGE_TRIGGER'; +export * from './triggers'; diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts new file mode 100644 index 0000000000000..491d9e730eb75 --- /dev/null +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -0,0 +1,65 @@ +/* + * 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 { Trigger } from '../../../../ui_actions/public'; +import { IEmbeddable } from '..'; + +export interface EmbeddableVisTriggerContext { + embeddable: IEmbeddable; + timeFieldName: string; + data: { + e: MouseEvent; + data: unknown; + }; +} + +export const SELECT_RANGE_TRIGGER = 'SELECT_RANGE_TRIGGER'; +export const selectRangeTrigger: Trigger<'SELECT_RANGE_TRIGGER'> = { + id: SELECT_RANGE_TRIGGER, + title: 'Select range', + description: 'Applies a range filter', +}; + +export const VALUE_CLICK_TRIGGER = 'VALUE_CLICK_TRIGGER'; +export const valueClickTrigger: Trigger<'VALUE_CLICK_TRIGGER'> = { + id: VALUE_CLICK_TRIGGER, + title: 'Value clicked', + description: 'Value was clicked', +}; + +export const CONTEXT_MENU_TRIGGER = 'CONTEXT_MENU_TRIGGER'; +export const contextMenuTrigger: Trigger<'CONTEXT_MENU_TRIGGER'> = { + id: CONTEXT_MENU_TRIGGER, + title: 'Context menu', + description: 'Triggered on top-right corner context-menu select.', +}; + +export const APPLY_FILTER_TRIGGER = 'FILTER_TRIGGER'; +export const applyFilterTrigger: Trigger<'FILTER_TRIGGER'> = { + id: APPLY_FILTER_TRIGGER, + title: 'Filter click', + description: 'Triggered when user applies filter to an embeddable.', +}; + +export const PANEL_BADGE_TRIGGER = 'PANEL_BADGE_TRIGGER'; +export const panelBadgeTrigger: Trigger<'PANEL_BADGE_TRIGGER'> = { + id: PANEL_BADGE_TRIGGER, + title: 'Panel badges', + description: 'Actions appear in title bar when an embeddable loads in a panel', +}; diff --git a/src/plugins/ui_actions/public/index.ts b/src/plugins/ui_actions/public/index.ts index 83a08b11fa4c2..1ce48d5460b2e 100644 --- a/src/plugins/ui_actions/public/index.ts +++ b/src/plugins/ui_actions/public/index.ts @@ -29,7 +29,8 @@ export { UiActionsSetup, UiActionsStart } from './plugin'; export { UiActionsServiceParams, UiActionsService } from './service'; export { Action, createAction, IncompatibleActionError } from './actions'; export { buildContextMenuForActions } from './context_menu'; -export { Trigger } from './triggers'; +export { Trigger, TriggerContext } from './triggers'; +export { TriggerContextMapping } from './types'; /** * @deprecated diff --git a/src/plugins/ui_actions/public/service/ui_actions_service.test.ts b/src/plugins/ui_actions/public/service/ui_actions_service.test.ts index 2bbe106c49a25..8963ba4ddb005 100644 --- a/src/plugins/ui_actions/public/service/ui_actions_service.test.ts +++ b/src/plugins/ui_actions/public/service/ui_actions_service.test.ts @@ -68,7 +68,7 @@ describe('UiActionsService', () => { const trigger = service.getTrigger('bar'); - expect(trigger).toEqual({ + expect(trigger).toMatchObject({ description: 'foo', id: 'bar', title: 'baz', @@ -345,8 +345,9 @@ describe('UiActionsService', () => { id: 'bar', title: 'baz', }); + const triggerContract = service.getTrigger('bar'); - expect(triggers.get('bar')).toEqual({ + expect(triggerContract).toMatchObject({ description: 'foo', id: 'bar', title: 'baz', diff --git a/src/plugins/ui_actions/public/service/ui_actions_service.ts b/src/plugins/ui_actions/public/service/ui_actions_service.ts index a62d2aa356435..ae409830bbb6e 100644 --- a/src/plugins/ui_actions/public/service/ui_actions_service.ts +++ b/src/plugins/ui_actions/public/service/ui_actions_service.ts @@ -17,10 +17,11 @@ * under the License. */ -import { TriggerRegistry, ActionRegistry, TriggerToActionsRegistry } from '../types'; +import { TriggerRegistry, ActionRegistry, TriggerToActionsRegistry, TriggerId } from '../types'; import { Action } from '../actions'; -import { Trigger } from '../triggers/trigger'; -import { buildContextMenuForActions, openContextMenu } from '../context_menu'; +import { Trigger, TriggerContext } from '../triggers/trigger'; +import { TriggerInternal } from '../triggers/trigger_internal'; +import { TriggerContract } from '../triggers/trigger_contract'; export interface UiActionsServiceParams { readonly triggers?: TriggerRegistry; @@ -52,18 +53,20 @@ export class UiActionsService { throw new Error(`Trigger [trigger.id = ${trigger.id}] already registered.`); } - this.triggers.set(trigger.id, trigger); + const triggerInternal = new TriggerInternal(this, trigger); + + this.triggers.set(trigger.id, triggerInternal); this.triggerToActions.set(trigger.id, []); }; - public readonly getTrigger = (id: string) => { - const trigger = this.triggers.get(id); + public readonly getTrigger = (triggerId: T): TriggerContract => { + const trigger = this.triggers.get(triggerId as string); if (!trigger) { - throw new Error(`Trigger [triggerId = ${id}] does not exist.`); + throw new Error(`Trigger [triggerId = ${triggerId}] does not exist.`); } - return trigger; + return trigger.contract; }; public readonly registerAction = (action: Action) => { @@ -128,41 +131,17 @@ export class UiActionsService { ); }; - private async executeSingleAction(action: Action, actionContext: A) { - const href = action.getHref && action.getHref(actionContext); - - if (href) { - window.location.href = href; - return; - } - - await action.execute(actionContext); - } - - private async executeMultipleActions(actions: Action[], actionContext: C) { - const panel = await buildContextMenuForActions({ - actions, - actionContext, - closeMenu: () => session.close(), - }); - const session = openContextMenu([panel]); - } - - public readonly executeTriggerActions = async (triggerId: string, actionContext: C) => { - const actions = await this.getTriggerCompatibleActions!(triggerId, actionContext); - - if (!actions.length) { - throw new Error( - `No compatible actions found to execute for trigger [triggerId = ${triggerId}].` - ); - } - - if (actions.length === 1) { - await this.executeSingleAction(actions[0], actionContext); - return; - } - - await this.executeMultipleActions(actions, actionContext); + /** + * @deprecated + * + * Use `plugins.uiActions.getTrigger(triggerId).exec(params)` instead. + */ + public readonly executeTriggerActions = async ( + triggerId: T, + context: TriggerContext + ) => { + const trigger = this.getTrigger(triggerId); + await trigger.exec(context); }; /** diff --git a/src/plugins/ui_actions/public/triggers/index.ts b/src/plugins/ui_actions/public/triggers/index.ts index a34c6eda61ba0..1ae2a19c4001f 100644 --- a/src/plugins/ui_actions/public/triggers/index.ts +++ b/src/plugins/ui_actions/public/triggers/index.ts @@ -17,4 +17,6 @@ * under the License. */ -export { Trigger } from './trigger'; +export * from './trigger'; +export * from './trigger_contract'; +export * from './trigger_internal'; diff --git a/src/plugins/ui_actions/public/triggers/trigger.ts b/src/plugins/ui_actions/public/triggers/trigger.ts index ba83f5619e250..2c019b09881d1 100644 --- a/src/plugins/ui_actions/public/triggers/trigger.ts +++ b/src/plugins/ui_actions/public/triggers/trigger.ts @@ -17,8 +17,35 @@ * under the License. */ -export interface Trigger { - id: string; +import { TriggerContextMapping, TriggerId } from '../types'; + +/** + * This is a convenience interface used to register a *trigger*. + * + * `Trigger` specifies a named anchor to which `Action` can be attached. When + * `Trigger` is being *called* it creates a `Context` object and passes it to + * the `execute` method of an `Action`. + * + * More than one action can be attached to a single trigger, in which case when + * trigger is *called* it first displays a context menu for user to pick a + * single action to execute. + */ +export interface Trigger { + /** + * Unique name of the trigger as identified in `ui_actions` plugin trigger + * registry, such as "SELECT_RANGE_TRIGGER" or "VALUE_CLICK_TRIGGER". + */ + id: ID; + + /** + * User friendly name of the trigger. + */ title?: string; + + /** + * A longer user friendly description of the trigger. + */ description?: string; } + +export type TriggerContext = T extends TriggerId ? TriggerContextMapping[T] : never; diff --git a/src/plugins/ui_actions/public/triggers/trigger_contract.ts b/src/plugins/ui_actions/public/triggers/trigger_contract.ts new file mode 100644 index 0000000000000..853b83dccabcc --- /dev/null +++ b/src/plugins/ui_actions/public/triggers/trigger_contract.ts @@ -0,0 +1,56 @@ +/* + * 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 { TriggerContext } from './trigger'; +import { TriggerInternal } from './trigger_internal'; +import { TriggerId } from '../types'; + +/** + * This is a public representation of a trigger that is provided to other plugins. + */ +export class TriggerContract { + /** + * Unique name of the trigger as identified in `ui_actions` plugin trigger + * registry, such as "SELECT_RANGE_TRIGGER" or "VALUE_CLICK_TRIGGER". + */ + public readonly id: T; + + /** + * User friendly name of the trigger. + */ + public readonly title?: string; + + /** + * A longer user friendly description of the trigger. + */ + public readonly description?: string; + + constructor(private readonly internal: TriggerInternal) { + this.id = this.internal.trigger.id; + this.title = this.internal.trigger.title; + this.description = this.internal.trigger.description; + } + + /** + * Use this method to execute action attached to this trigger. + */ + public readonly exec = async (context: TriggerContext) => { + await this.internal.execute(context); + }; +} diff --git a/src/plugins/ui_actions/public/triggers/trigger_internal.ts b/src/plugins/ui_actions/public/triggers/trigger_internal.ts new file mode 100644 index 0000000000000..efcdc72ecad57 --- /dev/null +++ b/src/plugins/ui_actions/public/triggers/trigger_internal.ts @@ -0,0 +1,76 @@ +/* + * 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 { TriggerContext, Trigger } from './trigger'; +import { TriggerContract } from './trigger_contract'; +import { UiActionsService } from '../service'; +import { Action } from '../actions'; +import { buildContextMenuForActions, openContextMenu } from '../context_menu'; +import { TriggerId } from '../types'; + +/** + * Internal representation of a trigger kept for consumption only internally + * within `ui_actions` plugin. + */ +export class TriggerInternal { + public readonly contract = new TriggerContract(this); + + constructor(public readonly service: UiActionsService, public readonly trigger: Trigger) {} + + public async execute(context: TriggerContext) { + const triggerId = this.trigger.id; + const actions = await this.service.getTriggerCompatibleActions!(triggerId, context); + + if (!actions.length) { + throw new Error( + `No compatible actions found to execute for trigger [triggerId = ${triggerId}].` + ); + } + + if (actions.length === 1) { + await this.executeSingleAction(actions[0], context); + return; + } + + await this.executeMultipleActions(actions, context); + } + + private async executeSingleAction(action: Action>, context: TriggerContext) { + const href = action.getHref && action.getHref(context); + + if (href) { + window.location.href = href; + return; + } + + await action.execute(context); + } + + private async executeMultipleActions( + actions: Array>>, + context: TriggerContext + ) { + const panel = await buildContextMenuForActions({ + actions, + actionContext: context, + closeMenu: () => session.close(), + }); + const session = openContextMenu([panel]); + } +} diff --git a/src/plugins/ui_actions/public/types.ts b/src/plugins/ui_actions/public/types.ts index 9bd6ffdef2af3..8daa893eb4347 100644 --- a/src/plugins/ui_actions/public/types.ts +++ b/src/plugins/ui_actions/public/types.ts @@ -18,8 +18,14 @@ */ import { Action } from './actions/action'; -import { Trigger } from './triggers/trigger'; +import { TriggerInternal } from './triggers/trigger_internal'; -export type TriggerRegistry = Map; +export type TriggerRegistry = Map>; export type ActionRegistry = Map; export type TriggerToActionsRegistry = Map; + +export type TriggerId = string; + +export interface TriggerContextMapping { + [key: string]: object; +} From c91b6ceebcec85cf0991da555ba94605e5fcb029 Mon Sep 17 00:00:00 2001 From: Brandon Kobel Date: Fri, 21 Feb 2020 07:27:40 -0800 Subject: [PATCH 004/123] Updating to @elastic/lodash@3.10.1-kibana4 (#54662) Co-authored-by: Elastic Machine --- package.json | 2 +- packages/kbn-interpreter/package.json | 2 +- packages/kbn-ui-framework/package.json | 2 +- x-pack/package.json | 2 +- yarn.lock | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index b11234b6312e9..cb87c48ab7f2a 100644 --- a/package.json +++ b/package.json @@ -205,7 +205,7 @@ "leaflet.heat": "0.2.0", "less": "^2.7.3", "less-loader": "5.0.0", - "lodash": "npm:@elastic/lodash@3.10.1-kibana3", + "lodash": "npm:@elastic/lodash@3.10.1-kibana4", "lodash.clonedeep": "^4.5.0", "lru-cache": "4.1.5", "markdown-it": "^10.0.0", diff --git a/packages/kbn-interpreter/package.json b/packages/kbn-interpreter/package.json index d2f0b0c358284..5dede7fbf1aaa 100644 --- a/packages/kbn-interpreter/package.json +++ b/packages/kbn-interpreter/package.json @@ -11,7 +11,7 @@ "dependencies": { "@babel/runtime": "^7.5.5", "@kbn/i18n": "1.0.0", - "lodash": "npm:@elastic/lodash@3.10.1-kibana3", + "lodash": "npm:@elastic/lodash@3.10.1-kibana4", "lodash.clone": "^4.5.0", "uuid": "3.3.2" }, diff --git a/packages/kbn-ui-framework/package.json b/packages/kbn-ui-framework/package.json index fc245ca3fe921..0402a83d3d274 100644 --- a/packages/kbn-ui-framework/package.json +++ b/packages/kbn-ui-framework/package.json @@ -17,7 +17,7 @@ "dependencies": { "classnames": "2.2.6", "focus-trap-react": "^3.1.1", - "lodash": "npm:@elastic/lodash@3.10.1-kibana3", + "lodash": "npm:@elastic/lodash@3.10.1-kibana4", "prop-types": "15.6.0", "react": "^16.12.0", "react-ace": "^5.9.0", diff --git a/x-pack/package.json b/x-pack/package.json index 9d6b5d76a58e7..551e466893f93 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -262,7 +262,7 @@ "json-stable-stringify": "^1.0.1", "jsonwebtoken": "^8.5.1", "jsts": "^1.6.2", - "lodash": "npm:@elastic/lodash@3.10.1-kibana3", + "lodash": "npm:@elastic/lodash@3.10.1-kibana4", "lodash.keyby": "^4.6.0", "lodash.mean": "^4.1.0", "lodash.topath": "^4.5.2", diff --git a/yarn.lock b/yarn.lock index 6b3370407e3b2..2caaac974dfad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19812,10 +19812,10 @@ lodash@^3.10.1: resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y= -"lodash@npm:@elastic/lodash@3.10.1-kibana3": - version "3.10.1-kibana3" - resolved "https://registry.yarnpkg.com/@elastic/lodash/-/lodash-3.10.1-kibana3.tgz#c0e318245219eeeff535895c429e0cef5058a9ad" - integrity sha512-HMfwwT2yAkEQNzHSR1BxgE5YcDMUaZ/skhNyjy1nvM/A4m0Kh940hLZeCqKBCsSaUJz/8A/9cQGd9BaAOCIBLg== +"lodash@npm:@elastic/lodash@3.10.1-kibana4": + version "3.10.1-kibana4" + resolved "https://registry.yarnpkg.com/@elastic/lodash/-/lodash-3.10.1-kibana4.tgz#d491228fd659b4a1b0dfa08ba9c67a4979b9746d" + integrity sha512-geQqXd9ZedRCL+kq5cpeahYWYaYRV0BMXhCwzq4DpnGCVs430FTMS3Wcot3XChZZhCvkwHm15bpNjB312vPxaA== log-ok@^0.1.1: version "0.1.1" From 38988dae7118b0e71db6c3cf73d87ca9e816ee5c Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Fri, 21 Feb 2020 16:54:53 +0100 Subject: [PATCH 005/123] Do not refresh color scale on each lookup (#57792) --- .../public/components/__tests__/tag_cloud.js | 26 +++++++++---------- .../public/components/tag_cloud.js | 7 +++-- .../components/tag_cloud_visualization.js | 4 ++- .../new_platform/new_platform.karma_mock.js | 3 +++ 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud.js b/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud.js index 136fe51674bf1..152efe5667f18 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud.js +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/__tests__/tag_cloud.js @@ -30,10 +30,6 @@ import simpleloadPng from './simpleload.png'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { seedColors } from '../../../../../../plugins/charts/public/services/colors/seed_colors'; -const colors = { - seedColors, -}; - describe('tag cloud tests', function() { const minValue = 1; const maxValue = 9; @@ -102,6 +98,8 @@ describe('tag cloud tests', function() { let domNode; let tagCloud; + const colorScale = d3.scale.ordinal().range(seedColors); + function setupDOM() { domNode = document.createElement('div'); domNode.style.top = '0'; @@ -132,7 +130,7 @@ describe('tag cloud tests', function() { )}`, function() { beforeEach(async function() { setupDOM(); - tagCloud = new TagCloud(domNode, colors); + tagCloud = new TagCloud(domNode, colorScale); tagCloud.setData(test.data); tagCloud.setOptions(test.options); await fromNode(cb => tagCloud.once('renderComplete', cb)); @@ -164,7 +162,7 @@ describe('tag cloud tests', function() { //TagCloud takes at least 600ms to complete (due to d3 animation) //renderComplete should only notify at the last one - tagCloud = new TagCloud(domNode, colors); + tagCloud = new TagCloud(domNode, colorScale); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); @@ -196,7 +194,7 @@ describe('tag cloud tests', function() { describe('should use the latest state before notifying (when modifying options multiple times)', function() { beforeEach(async function() { setupDOM(); - tagCloud = new TagCloud(domNode, colors); + tagCloud = new TagCloud(domNode, colorScale); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); tagCloud.setOptions(logScaleTest.options); @@ -223,7 +221,7 @@ describe('tag cloud tests', function() { describe('should use the latest state before notifying (when modifying data multiple times)', function() { beforeEach(async function() { setupDOM(); - tagCloud = new TagCloud(domNode, colors); + tagCloud = new TagCloud(domNode, colorScale); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); tagCloud.setData(trimDataTest.data); @@ -253,7 +251,7 @@ describe('tag cloud tests', function() { counter = 0; setupDOM(); return new Promise((resolve, reject) => { - tagCloud = new TagCloud(domNode, colors); + tagCloud = new TagCloud(domNode, colorScale); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); @@ -299,7 +297,7 @@ describe('tag cloud tests', function() { describe('should show correct data when state-updates are interleaved with resize event', function() { beforeEach(async function() { setupDOM(); - tagCloud = new TagCloud(domNode, colors); + tagCloud = new TagCloud(domNode, colorScale); tagCloud.setData(logScaleTest.data); tagCloud.setOptions(logScaleTest.options); @@ -337,7 +335,7 @@ describe('tag cloud tests', function() { setupDOM(); domNode.style.width = '1px'; domNode.style.height = '1px'; - tagCloud = new TagCloud(domNode, colors); + tagCloud = new TagCloud(domNode, colorScale); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); await fromNode(cb => tagCloud.once('renderComplete', cb)); @@ -363,7 +361,7 @@ describe('tag cloud tests', function() { domNode.style.width = '1px'; domNode.style.height = '1px'; - tagCloud = new TagCloud(domNode, colors); + tagCloud = new TagCloud(domNode, colorScale); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); await fromNode(cb => tagCloud.once('renderComplete', cb)); @@ -388,7 +386,7 @@ describe('tag cloud tests', function() { describe(`tags should no longer fit after making container smaller`, function() { beforeEach(async function() { setupDOM(); - tagCloud = new TagCloud(domNode, colors); + tagCloud = new TagCloud(domNode, colorScale); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); await fromNode(cb => tagCloud.once('renderComplete', cb)); @@ -420,7 +418,7 @@ describe('tag cloud tests', function() { }); it('should render simple image', async function() { - tagCloud = new TagCloud(domNode, colors); + tagCloud = new TagCloud(domNode, colorScale); tagCloud.setData(baseTest.data); tagCloud.setOptions(baseTest.options); diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud.js b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud.js index f5084fd92cfee..fae7cdf797958 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud.js +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud.js @@ -37,7 +37,7 @@ const D3_SCALING_FUNCTIONS = { }; export class TagCloud extends EventEmitter { - constructor(domNode, colors) { + constructor(domNode, colorScale) { super(); //DOM @@ -54,7 +54,6 @@ export class TagCloud extends EventEmitter { this._spiral = 'archimedean'; //layout shape this._timeInterval = 1000; //time allowed for layout algorithm this._padding = 5; - this._seedColors = colors.seedColors; //OPTIONS this._orientation = 'single'; @@ -67,6 +66,7 @@ export class TagCloud extends EventEmitter { this._words = null; //UTIL + this._colorScale = colorScale; this._setTimeoutId = null; this._pendingJob = null; this._layoutIsUpdating = null; @@ -371,8 +371,7 @@ export class TagCloud extends EventEmitter { } getFill(tag) { - const colorScale = d3.scale.ordinal().range(this._seedColors); - return colorScale(tag.text); + return this._colorScale(tag.text); } } diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js index 5528278adf4eb..114643c9a74e0 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js @@ -28,10 +28,12 @@ import { getFormat } from '../legacy_imports'; import { Label } from './label'; import { TagCloud } from './tag_cloud'; import { FeedbackMessage } from './feedback_message'; +import d3 from 'd3'; const MAX_TAG_COUNT = 200; export function createTagCloudVisualization({ colors }) { + const colorScale = d3.scale.ordinal().range(colors.seedColors); return class TagCloudVisualization { constructor(node, vis) { this._containerNode = node; @@ -48,7 +50,7 @@ export function createTagCloudVisualization({ colors }) { this._vis = vis; this._truncated = false; - this._tagCloud = new TagCloud(cloudContainer, colors); + this._tagCloud = new TagCloud(cloudContainer, colorScale); this._tagCloud.on('select', event => { if (!this._visParams.bucket) { return; diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index 38b3434ef9c48..cf8537ba7ab3e 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -218,6 +218,9 @@ export const npSetup = { chartsTheme$: mockObservable, useChartsTheme: sinon.fake(), }, + colors: { + seedColors: ['white', 'black'], + }, }, management: { sections: { From 8686fc99dc841f0c3463cb80da53c83f0d24763c Mon Sep 17 00:00:00 2001 From: Spencer Date: Fri, 21 Feb 2020 09:14:28 -0700 Subject: [PATCH 006/123] [kbn/optimizer] include bootstrap cache key in optimizer cache key (#58176) * [kbn/optimizer] include bootstrap cache key in optimizer cache key * remove cache buster * update cache keys tests * move mocks --- packages/kbn-optimizer/src/index.ts | 1 - .../src/optimizer/cache_keys.test.ts | 52 ++++++++++++++----- .../kbn-optimizer/src/optimizer/cache_keys.ts | 43 ++++++++++++--- 3 files changed, 75 insertions(+), 21 deletions(-) diff --git a/packages/kbn-optimizer/src/index.ts b/packages/kbn-optimizer/src/index.ts index 9798391d47da4..48777f1d54aaf 100644 --- a/packages/kbn-optimizer/src/index.ts +++ b/packages/kbn-optimizer/src/index.ts @@ -17,7 +17,6 @@ * under the License. */ -// cache buster - https://github.com/elastic/kibana/issues/58077 - 1 export { OptimizerConfig } from './optimizer'; export * from './run_optimizer'; export * from './log_optimizer_state'; diff --git a/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts b/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts index 44234acd897dc..2337017f54ed8 100644 --- a/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts +++ b/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts @@ -17,14 +17,35 @@ * under the License. */ +import Path from 'path'; + import jestDiff from 'jest-diff'; import { REPO_ROOT, createAbsolutePathSerializer } from '@kbn/dev-utils'; import { reformatJestDiff, getOptimizerCacheKey, diffCacheKey } from './cache_keys'; import { OptimizerConfig } from './optimizer_config'; -jest.mock('./get_changes.ts'); +jest.mock('./get_changes.ts', () => ({ + getChanges: async () => + new Map([ + ['/foo/bar/a', 'modified'], + ['/foo/bar/b', 'modified'], + ['/foo/bar/c', 'deleted'], + ]), +})); + +jest.mock('./get_mtimes.ts', () => ({ + getMtimes: async (paths: string[]) => new Map(paths.map(path => [path, 12345])), +})); + jest.mock('execa'); + +jest.mock('fs', () => { + const realFs = jest.requireActual('fs'); + jest.spyOn(realFs, 'readFile'); + return realFs; +}); + expect.addSnapshotSerializer(createAbsolutePathSerializer()); jest.requireMock('execa').mockImplementation(async (cmd: string, args: string[], opts: object) => { @@ -46,28 +67,35 @@ jest.requireMock('execa').mockImplementation(async (cmd: string, args: string[], }; }); -jest.requireMock('./get_changes.ts').getChanges.mockImplementation( - async () => - new Map([ - ['/foo/bar/a', 'modified'], - ['/foo/bar/b', 'modified'], - ['/foo/bar/c', 'deleted'], - ]) -); - describe('getOptimizerCacheKey()', () => { - it('uses latest commit and changes files to create unique value', async () => { + it('uses latest commit, bootstrap cache, and changed files to create unique value', async () => { + jest + .requireMock('fs') + .readFile.mockImplementation( + (path: string, enc: string, cb: (err: null, file: string) => void) => { + expect(path).toBe( + Path.resolve(REPO_ROOT, 'packages/kbn-optimizer/target/.bootstrap-cache') + ); + expect(enc).toBe('utf8'); + cb(null, ''); + } + ); + const config = OptimizerConfig.create({ repoRoot: REPO_ROOT, }); await expect(getOptimizerCacheKey(config)).resolves.toMatchInlineSnapshot(` Object { + "bootstrap": "", "deletedPaths": Array [ "/foo/bar/c", ], "lastCommit": "", - "modifiedPaths": Object {}, + "modifiedTimes": Object { + "/foo/bar/a": 12345, + "/foo/bar/b": 12345, + }, "workerConfig": Object { "browserslistEnv": "dev", "cache": true, diff --git a/packages/kbn-optimizer/src/optimizer/cache_keys.ts b/packages/kbn-optimizer/src/optimizer/cache_keys.ts index 3529ffa587f16..af6a8a648d29c 100644 --- a/packages/kbn-optimizer/src/optimizer/cache_keys.ts +++ b/packages/kbn-optimizer/src/optimizer/cache_keys.ts @@ -18,6 +18,8 @@ */ import Path from 'path'; +import Fs from 'fs'; +import { promisify } from 'util'; import Chalk from 'chalk'; import execa from 'execa'; @@ -116,9 +118,10 @@ export function reformatJestDiff(diff: string | null) { export interface OptimizerCacheKey { readonly lastCommit: string | undefined; + readonly bootstrap: string | undefined; readonly workerConfig: WorkerConfig; readonly deletedPaths: string[]; - readonly modifiedPaths: Record; + readonly modifiedTimes: Record; } async function getLastCommit() { @@ -133,21 +136,45 @@ async function getLastCommit() { return stdout.trim() || undefined; } +async function getBootstrapCacheKey() { + try { + return await promisify(Fs.readFile)( + Path.resolve(OPTIMIZER_DIR, 'target/.bootstrap-cache'), + 'utf8' + ); + } catch (error) { + if (error?.code !== 'ENOENT') { + throw error; + } + return undefined; + } +} + export async function getOptimizerCacheKey(config: OptimizerConfig) { - const changes = Array.from((await getChanges(OPTIMIZER_DIR)).entries()); + const [changes, lastCommit, bootstrap] = await Promise.all([ + getChanges(OPTIMIZER_DIR), + getLastCommit(), + getBootstrapCacheKey(), + ] as const); + + const deletedPaths: string[] = []; + const modifiedPaths: string[] = []; + for (const [path, type] of changes) { + (type === 'deleted' ? deletedPaths : modifiedPaths).push(path); + } const cacheKeys: OptimizerCacheKey = { - lastCommit: await getLastCommit(), workerConfig: config.getWorkerConfig('♻'), - deletedPaths: changes.filter(e => e[1] === 'deleted').map(e => e[0]), - modifiedPaths: {} as Record, + lastCommit, + bootstrap, + deletedPaths, + modifiedTimes: {} as Record, }; - const modified = changes.filter(e => e[1] === 'modified').map(e => e[0]); - const mtimes = await getMtimes(modified); + const mtimes = await getMtimes(modifiedPaths); for (const [path, mtime] of Array.from(mtimes.entries()).sort(ascending(e => e[0]))) { if (typeof mtime === 'number') { - cacheKeys.modifiedPaths[path] = mtime; + cacheKeys.modifiedTimes[path] = mtime; } } From fb04b7afb4cd644e68fa4bb3a5f1da60f799ae35 Mon Sep 17 00:00:00 2001 From: Charlie Pichette <56399229+charlie-pichette@users.noreply.github.com> Date: Fri, 21 Feb 2020 11:44:57 -0500 Subject: [PATCH 007/123] [Endpoint] Refactor Management List Tests (#58148) * endpoint-161-refactor-management-list-test * fix location of es archive file --- .../functional/apps/endpoint/management.ts | 68 +++++++++++++++---- .../endpoint/metadata/api_feature/data.json | 6 +- .../functional/page_objects/endpoint_page.ts | 27 +++++++- 3 files changed, 82 insertions(+), 19 deletions(-) diff --git a/x-pack/test/functional/apps/endpoint/management.ts b/x-pack/test/functional/apps/endpoint/management.ts index 500185182f0d8..4925fa7678ab0 100644 --- a/x-pack/test/functional/apps/endpoint/management.ts +++ b/x-pack/test/functional/apps/endpoint/management.ts @@ -25,19 +25,61 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('displays table data', async () => { - const data = await pageObjects.endpoint.getManagementTableData(); - [ - 'Hostnamecadmann-4.example.com', - 'PolicyPolicy Name', - 'Policy StatusPolicy Status', - 'Alerts0', - 'Operating Systemwindows 10.0', - 'IP Address10.192.213.130, 10.70.28.129', - 'Sensor Versionversion', - 'Last Activexxxx', - ].forEach((cellValue, index) => { - expect(data[1][index]).to.equal(cellValue); - }); + const expectedData = [ + [ + 'Hostname', + 'Policy', + 'Policy Status', + 'Alerts', + 'Operating System', + 'IP Address', + 'Sensor Version', + 'Last Active', + ], + [ + 'cadmann-4.example.com', + 'Policy Name', + 'Policy Status', + '0', + 'windows 10.0', + '10.192.213.130, 10.70.28.129', + 'version', + 'xxxx', + ], + [ + 'thurlow-9.example.com', + 'Policy Name', + 'Policy Status', + '0', + 'windows 10.0', + '10.46.229.234', + 'version', + 'xxxx', + ], + [ + 'rezzani-7.example.com', + 'Policy Name', + 'Policy Status', + '0', + 'windows 10.0', + '10.101.149.26, 2606:a000:ffc0:39:11ef:37b9:3371:578c', + 'version', + 'xxxx', + ], + ]; + const tableData = await pageObjects.endpoint.getEndpointAppTableData('managementListTable'); + expect(tableData).to.eql(expectedData); + }); + + it('displays no items found', async () => { + // clear out the data and reload the page + await esArchiver.unload('endpoint/metadata/api_feature'); + await pageObjects.common.navigateToUrlWithBrowserHistory('endpoint', '/management'); + // get the table data and verify no entries appear + const tableData = await pageObjects.endpoint.getEndpointAppTableData('managementListTable'); + expect(tableData[1][0]).to.equal('No items found'); + // reload the data so the other tests continue to pass + await esArchiver.load('endpoint/metadata/api_feature'); }); after(async () => { diff --git a/x-pack/test/functional/es_archives/endpoint/metadata/api_feature/data.json b/x-pack/test/functional/es_archives/endpoint/metadata/api_feature/data.json index 87720b068f0e8..6a7911b5be61f 100644 --- a/x-pack/test/functional/es_archives/endpoint/metadata/api_feature/data.json +++ b/x-pack/test/functional/es_archives/endpoint/metadata/api_feature/data.json @@ -110,7 +110,7 @@ "id": "fc0ff548-feba-41b6-8367-65e8790d0eaf", "ip": [ "10.101.149.26", - "10.12.85.216" + "2606:a000:ffc0:39:11ef:37b9:3371:578c" ], "mac": [ "e2-6d-f9-0-46-2e" @@ -238,7 +238,7 @@ "id": "fc0ff548-feba-41b6-8367-65e8790d0eaf", "ip": [ "10.101.149.26", - "10.12.85.216" + "2606:a000:ffc0:39:11ef:37b9:3371:578c" ], "mac": [ "e2-6d-f9-0-46-2e" @@ -365,7 +365,7 @@ "id": "fc0ff548-feba-41b6-8367-65e8790d0eaf", "ip": [ "10.101.149.26", - "10.12.85.216" + "2606:a000:ffc0:39:11ef:37b9:3371:578c" ], "mac": [ "e2-6d-f9-0-46-2e" diff --git a/x-pack/test/functional/page_objects/endpoint_page.ts b/x-pack/test/functional/page_objects/endpoint_page.ts index 54f537dd0e8c3..185b95b00527d 100644 --- a/x-pack/test/functional/page_objects/endpoint_page.ts +++ b/x-pack/test/functional/page_objects/endpoint_page.ts @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ +import { WebElementWrapper } from 'test/functional/services/lib/web_element_wrapper'; import { FtrProviderContext } from '../ftr_provider_context'; export function EndpointPageProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); - const table = getService('table'); return { /** @@ -34,8 +34,29 @@ export function EndpointPageProvider({ getService }: FtrProviderContext) { return await testSubjects.getVisibleText('welcomeTitle'); }, - async getManagementTableData() { - return await table.getDataFromTestSubj('managementListTable'); + /** + * Finds a table and returns the data in a nested array with row 0 is the headers if they exist. + * It uses euiTableCellContent to avoid poluting the array data with the euiTableRowCell__mobileHeader data. + * @param dataTestSubj + * @returns Promise + */ + async getEndpointAppTableData(dataTestSubj: string) { + await testSubjects.exists(dataTestSubj); + const hostTable: WebElementWrapper = await testSubjects.find(dataTestSubj); + const $ = await hostTable.parseDomContent(); + return $('tr') + .toArray() + .map(row => + $(row) + .find('.euiTableCellContent') + .toArray() + .map(cell => + $(cell) + .text() + .replace(/ /g, '') + .trim() + ) + ); }, }; } From 3d9eb2a679f6316548f156ed5c9e705ea45a7bf6 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Fri, 21 Feb 2020 17:45:42 +0100 Subject: [PATCH 008/123] [ML] Transform: Support multi-line JSON notation in advanced editor (#58015) * [ML] use xJsonMode * [ML] remove commented code * [ML] move use_x_json_mode hook, disable json formatting * [ML] mocks for shared_imports * [ML] ts-ignore worker import --- .../public/__mocks__/shared_imports.ts | 10 +++++++++ .../public/app/hooks/use_x_json_mode.ts | 20 ++++++++++++++++++ .../source_index_preview.test.tsx | 2 ++ .../step_create/step_create_form.test.tsx | 2 ++ .../step_define/pivot_preview.test.tsx | 2 ++ .../step_define/step_define_form.test.tsx | 2 ++ .../step_define/step_define_form.tsx | 21 +++++++++++-------- .../step_define/step_define_summary.test.tsx | 2 ++ .../create_transform_button.test.tsx | 2 ++ .../transform_list/action_delete.test.tsx | 2 ++ .../transform_list/action_start.test.tsx | 2 ++ .../transform_list/action_stop.test.tsx | 2 ++ .../transform_list/actions.test.tsx | 2 ++ .../transform_list/columns.test.tsx | 2 ++ .../transform_list/expanded_row.test.tsx | 2 ++ .../transform_list/transform_list.test.tsx | 2 ++ .../transform_management_section.test.tsx | 2 ++ .../transform/public/shared_imports.ts | 6 ++++++ .../ace/modes/x_json/worker/index.ts | 1 + 19 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 x-pack/legacy/plugins/transform/public/__mocks__/shared_imports.ts create mode 100644 x-pack/legacy/plugins/transform/public/app/hooks/use_x_json_mode.ts diff --git a/x-pack/legacy/plugins/transform/public/__mocks__/shared_imports.ts b/x-pack/legacy/plugins/transform/public/__mocks__/shared_imports.ts new file mode 100644 index 0000000000000..b55a4cd5c7bd6 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/__mocks__/shared_imports.ts @@ -0,0 +1,10 @@ +/* + * 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 function XJsonMode() {} +export function setDependencyCache() {} +export { mlInMemoryTableBasicFactory } from '../../../ml/public/application/components/ml_in_memory_table'; +export const SORT_DIRECTION = { ASC: 'asc' }; diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/use_x_json_mode.ts b/x-pack/legacy/plugins/transform/public/app/hooks/use_x_json_mode.ts new file mode 100644 index 0000000000000..1017ce198ff29 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/hooks/use_x_json_mode.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { useState } from 'react'; +import { collapseLiteralStrings, expandLiteralStrings, XJsonMode } from '../../shared_imports'; + +export const xJsonMode = new XJsonMode(); + +export const useXJsonMode = (json: string) => { + const [xJson, setXJson] = useState(expandLiteralStrings(json)); + + return { + xJson, + setXJson, + xJsonMode, + convertToJson: collapseLiteralStrings, + }; +}; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.test.tsx index f326199271592..d7f1d9d099cc3 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.test.tsx @@ -20,6 +20,8 @@ jest.mock('react', () => { return { ...r, memo: (x: any) => x }; }); +jest.mock('../../../../../shared_imports'); + describe('Transform: ', () => { test('Minimal initialization', () => { const props = { diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx index 055f0613e4e44..a0c91c070844b 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx @@ -19,6 +19,8 @@ jest.mock('react', () => { return { ...r, memo: (x: any) => x }; }); +jest.mock('../../../../../shared_imports'); + describe('Transform: ', () => { test('Minimal initialization', () => { const props = { diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.test.tsx index 4ff1190415dba..a2aa056c1634d 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.test.tsx @@ -27,6 +27,8 @@ jest.mock('react', () => { return { ...r, memo: (x: any) => x }; }); +jest.mock('../../../../../shared_imports'); + describe('Transform: ', () => { test('Minimal initialization', () => { const groupBy: PivotGroupByConfig = { diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx index 48df371e87664..0311b26304c30 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx @@ -25,6 +25,8 @@ jest.mock('react', () => { return { ...r, memo: (x: any) => x }; }); +jest.mock('../../../../../shared_imports'); + describe('Transform: ', () => { test('Minimal initialization', () => { // Using a wrapping
element because shallow() would fail diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx index 675386be8e2a5..1499f99f82824 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx @@ -28,6 +28,7 @@ import { EuiSwitch, } from '@elastic/eui'; +import { useXJsonMode, xJsonMode } from '../../../../hooks/use_x_json_mode'; import { TransformPivotConfig } from '../../../../common'; import { dictionaryToArray, Dictionary } from '../../../../../../common/types/common'; import { DropDown } from '../aggregation_dropdown'; @@ -383,7 +384,13 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange const [advancedEditorConfigLastApplied, setAdvancedEditorConfigLastApplied] = useState( stringifiedPivotConfig ); - const [advancedEditorConfig, setAdvancedEditorConfig] = useState(stringifiedPivotConfig); + + const { + convertToJson, + setXJson: setAdvancedEditorConfig, + xJson: advancedEditorConfig, + } = useXJsonMode(stringifiedPivotConfig); + // source config const stringifiedSourceConfig = JSON.stringify(previewRequest.source.query, null, 2); const [ @@ -407,7 +414,7 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange }; const applyAdvancedPivotEditorChanges = () => { - const pivotConfig = JSON.parse(advancedEditorConfig); + const pivotConfig = JSON.parse(convertToJson(advancedEditorConfig)); const newGroupByList: PivotGroupByConfigDict = {}; if (pivotConfig !== undefined && pivotConfig.group_by !== undefined) { @@ -442,10 +449,8 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange }); } setAggList(newAggList); - const prettyPivotConfig = JSON.stringify(pivotConfig, null, 2); - setAdvancedEditorConfig(prettyPivotConfig); - setAdvancedEditorConfigLastApplied(prettyPivotConfig); + setAdvancedEditorConfigLastApplied(advancedEditorConfig); setAdvancedPivotEditorApplyButtonEnabled(false); }; @@ -513,13 +518,11 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange pivotAggsArr ); - const stringifiedPivotConfigUpdate = JSON.stringify(previewRequestUpdate.pivot, null, 2); const stringifiedSourceConfigUpdate = JSON.stringify( previewRequestUpdate.source.query, null, 2 ); - setAdvancedEditorConfig(stringifiedPivotConfigUpdate); setAdvancedEditorSourceConfig(stringifiedSourceConfigUpdate); onChange({ @@ -784,7 +787,7 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange > { @@ -799,7 +802,7 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange // Try to parse the string passed on from the editor. // If parsing fails, the "Apply"-Button will be disabled try { - JSON.parse(d); + JSON.parse(convertToJson(d)); setAdvancedPivotEditorApplyButtonEnabled(true); } catch (e) { setAdvancedPivotEditorApplyButtonEnabled(false); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx index 2d9895e8ddcf1..aae366e6008d5 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx @@ -26,6 +26,8 @@ jest.mock('react', () => { return { ...r, memo: (x: any) => x }; }); +jest.mock('../../../../../shared_imports'); + describe('Transform: ', () => { test('Minimal initialization', () => { const groupBy: PivotGroupByConfig = { diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx index 673e60de54572..288630333615a 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx @@ -11,6 +11,8 @@ import { CreateTransformButton } from './create_transform_button'; jest.mock('ui/new_platform'); +jest.mock('../../../../../shared_imports'); + describe('Transform: Transform List ', () => { test('Minimal initialization', () => { const wrapper = shallow(); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.test.tsx index 979da13b1f83a..4795a2eb7d7bc 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.test.tsx @@ -17,6 +17,8 @@ import transformListRow from '../../../../common/__mocks__/transform_list_row.js jest.mock('ui/new_platform'); +jest.mock('../../../../../shared_imports'); + describe('Transform: Transform List Actions ', () => { test('Minimal initialization', () => { const Providers = getAppProviders(createPublicShim()); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_start.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_start.test.tsx index 71a2eff39506d..5f4d4a71c71eb 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_start.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_start.test.tsx @@ -17,6 +17,8 @@ import transformListRow from '../../../../common/__mocks__/transform_list_row.js jest.mock('ui/new_platform'); +jest.mock('../../../../../shared_imports'); + describe('Transform: Transform List Actions ', () => { test('Minimal initialization', () => { const Providers = getAppProviders(createPublicShim()); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_stop.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_stop.test.tsx index c3b67f7661a1a..f6bb1c8b60667 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_stop.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_stop.test.tsx @@ -17,6 +17,8 @@ import transformListRow from '../../../../common/__mocks__/transform_list_row.js jest.mock('ui/new_platform'); +jest.mock('../../../../../shared_imports'); + describe('Transform: Transform List Actions ', () => { test('Minimal initialization', () => { const Providers = getAppProviders(createPublicShim()); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.test.tsx index ef92a5e3859d7..12e1ba5528c43 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.test.tsx @@ -8,6 +8,8 @@ import { getActions } from './actions'; jest.mock('ui/new_platform'); +jest.mock('../../../../../shared_imports'); + describe('Transform: Transform List Actions', () => { test('getActions()', () => { const actions = getActions({ forceDisable: false }); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/columns.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/columns.test.tsx index f16130bfe618b..42f04ed101ad6 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/columns.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/columns.test.tsx @@ -8,6 +8,8 @@ import { getColumns } from './columns'; jest.mock('ui/new_platform'); +jest.mock('../../../../../shared_imports'); + describe('Transform: Job List Columns', () => { test('getColumns()', () => { const columns = getColumns([], () => {}, []); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx index 4f992707cbf1a..7fcaf5e6048f6 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx @@ -13,6 +13,8 @@ import { ExpandedRow } from './expanded_row'; import transformListRow from '../../../../common/__mocks__/transform_list_row.json'; +jest.mock('../../../../../shared_imports'); + describe('Transform: Transform List ', () => { // Set timezone to US/Eastern for consistent test results. beforeEach(() => { diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx index 303de6b86ac53..e1a19ddd3c742 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx @@ -12,6 +12,8 @@ import { TransformList } from './transform_list'; jest.mock('ui/new_platform'); +jest.mock('../../../../../shared_imports'); + describe('Transform: Transform List ', () => { test('Minimal initialization', () => { const wrapper = shallow( diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx index c94f5c1d57d49..f68670f0b38b2 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx @@ -14,6 +14,8 @@ jest.mock('ui/timefilter', () => { return {}; }); +jest.mock('../../../shared_imports'); + describe('Transform: ', () => { test('Minimal initialization', () => { const wrapper = shallow(); diff --git a/x-pack/legacy/plugins/transform/public/shared_imports.ts b/x-pack/legacy/plugins/transform/public/shared_imports.ts index 74e0c9a3878db..248eb00c67dff 100644 --- a/x-pack/legacy/plugins/transform/public/shared_imports.ts +++ b/x-pack/legacy/plugins/transform/public/shared_imports.ts @@ -4,6 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ +export { XJsonMode } from '../../../../plugins/es_ui_shared/console_lang/ace/modes/x_json'; +export { + collapseLiteralStrings, + expandLiteralStrings, +} from '../../../../../src/plugins/es_ui_shared/console_lang/lib'; + export { SendRequestConfig, SendRequestResponse, diff --git a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/index.ts b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/index.ts index af50562bd3242..0e40fd335dd31 100644 --- a/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/index.ts +++ b/x-pack/plugins/es_ui_shared/console_lang/ace/modes/x_json/worker/index.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +// @ts-ignore import src from '!!raw-loader!./worker.js'; export const workerModule = { From 0adfdcafe137692750118277927f9a3ccbf26faa Mon Sep 17 00:00:00 2001 From: Corey Robertson Date: Fri, 21 Feb 2020 12:16:22 -0500 Subject: [PATCH 009/123] Sanitize workpad before sending to API (#57704) Co-authored-by: Elastic Machine --- .../canvas/public/lib/workpad_service.js | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/canvas/public/lib/workpad_service.js b/x-pack/legacy/plugins/canvas/public/lib/workpad_service.js index b678a532ec084..f3681f50c56a5 100644 --- a/x-pack/legacy/plugins/canvas/public/lib/workpad_service.js +++ b/x-pack/legacy/plugins/canvas/public/lib/workpad_service.js @@ -12,6 +12,35 @@ import { } from '../../common/lib/constants'; import { fetch } from '../../common/lib/fetch'; import { getCoreStart } from '../legacy'; +/* + Remove any top level keys from the workpad which will be rejected by validation +*/ +const validKeys = [ + '@created', + '@timestamp', + 'assets', + 'colors', + 'css', + 'height', + 'id', + 'isWriteable', + 'name', + 'page', + 'pages', + 'width', +]; + +const sanitizeWorkpad = function(workpad) { + const workpadKeys = Object.keys(workpad); + + for (const key of workpadKeys) { + if (!validKeys.includes(key)) { + delete workpad[key]; + } + } + + return workpad; +}; const getApiPath = function() { const basePath = getCoreStart().http.basePath.get(); @@ -29,7 +58,10 @@ const getApiPathAssets = function() { }; export function create(workpad) { - return fetch.post(getApiPath(), { ...workpad, assets: workpad.assets || {} }); + return fetch.post(getApiPath(), { + ...sanitizeWorkpad({ ...workpad }), + assets: workpad.assets || {}, + }); } export function get(workpadId) { @@ -41,11 +73,11 @@ export function get(workpadId) { // TODO: I think this function is never used. Look into and remove the corresponding route as well export function update(id, workpad) { - return fetch.put(`${getApiPath()}/${id}`, workpad); + return fetch.put(`${getApiPath()}/${id}`, sanitizeWorkpad({ ...workpad })); } export function updateWorkpad(id, workpad) { - return fetch.put(`${getApiPathStructures()}/${id}`, workpad); + return fetch.put(`${getApiPathStructures()}/${id}`, sanitizeWorkpad({ ...workpad })); } export function updateAssets(id, workpadAssets) { From cca7555c4b028a5d2a4bcd22241404aa547d6bef Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Fri, 21 Feb 2020 12:41:35 -0700 Subject: [PATCH 010/123] Make sure index pattern has fields before parsing (#58242) --- .../plugins/maps/server/maps_telemetry/maps_telemetry.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts b/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts index 87642d9f8bea8..863dbee7b5c8b 100644 --- a/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts +++ b/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts @@ -83,7 +83,11 @@ function getUniqueLayerCounts(layerCountsList: ILayerTypeCount[], mapsCount: num } function getIndexPatternsWithGeoFieldCount(indexPatterns: IIndexPattern[]) { - const fieldLists = indexPatterns.map(indexPattern => JSON.parse(indexPattern.attributes.fields)); + const fieldLists = indexPatterns.map(indexPattern => + indexPattern.attributes && indexPattern.attributes.fields + ? JSON.parse(indexPattern.attributes.fields) + : [] + ); const fieldListsWithGeoFields = fieldLists.filter(fields => fields.some( (field: IFieldType) => From 02efb01c481f9f24d8d707f06dfc68b2fb805001 Mon Sep 17 00:00:00 2001 From: Robert Austin Date: Fri, 21 Feb 2020 14:44:02 -0500 Subject: [PATCH 011/123] [Endpoint] Add a flyout to alert list. (#57926) * Filter alert API so it shows only Alerts instead of all documents in the index * Clicking an item in the alert list will open a flyout --- x-pack/plugins/endpoint/common/types.ts | 2 +- .../public/applications/endpoint/index.tsx | 15 +- .../endpoint/store/alerts/alert_list.test.ts | 33 +-- .../alerts/alert_list_pagination.test.ts | 63 +++--- .../endpoint/store/alerts/middleware.ts | 5 +- .../store/alerts/mock_alert_result_list.ts | 60 ++++++ .../endpoint/store/alerts/selectors.ts | 110 +++++----- .../applications/endpoint/store/index.ts | 43 ++-- .../public/applications/endpoint/types.ts | 37 +++- .../endpoint/view/alerts/index.test.tsx | 189 ++++++++++++++++++ .../endpoint/view/alerts/index.tsx | 159 +++++++++++---- .../view/alerts/url_from_query_params.ts | 31 +++ .../endpoint/view/route_capture.tsx | 21 ++ .../embeddables/resolver/store/selectors.ts | 1 - .../resolver/view/use_camera.test.tsx | 3 - .../endpoint/alert_query_builders.test.ts | 88 ++++---- .../services/endpoint/alert_query_builders.ts | 14 +- 17 files changed, 650 insertions(+), 224 deletions(-) create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/mock_alert_result_list.ts create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/view/alerts/index.test.tsx create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/view/alerts/url_from_query_params.ts create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/view/route_capture.tsx diff --git a/x-pack/plugins/endpoint/common/types.ts b/x-pack/plugins/endpoint/common/types.ts index f0fd9dc610e4e..78be98b7805ba 100644 --- a/x-pack/plugins/endpoint/common/types.ts +++ b/x-pack/plugins/endpoint/common/types.ts @@ -71,7 +71,7 @@ export interface EndpointResultList { } export interface AlertData { - '@timestamp': Date; + '@timestamp': string; agent: { id: string; version: string; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx index 8530d6206d398..c6c032c273543 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx @@ -8,16 +8,14 @@ import * as React from 'react'; import ReactDOM from 'react-dom'; import { CoreStart, AppMountParameters } from 'kibana/public'; import { I18nProvider, FormattedMessage } from '@kbn/i18n/react'; -import { Route, Switch, BrowserRouter, useLocation } from 'react-router-dom'; -import { Provider, useDispatch } from 'react-redux'; +import { Route, Switch, BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; import { Store } from 'redux'; -import { memo } from 'react'; +import { RouteCapture } from './view/route_capture'; import { appStoreFactory } from './store'; import { AlertIndex } from './view/alerts'; import { ManagementList } from './view/managing'; import { PolicyList } from './view/policy'; -import { AppAction } from './store/action'; -import { EndpointAppLocation } from './types'; /** * This module will be loaded asynchronously to reduce the bundle size of your plugin's main bundle. @@ -33,13 +31,6 @@ export function renderApp(coreStart: CoreStart, { appBasePath, element }: AppMou }; } -const RouteCapture = memo(({ children }) => { - const location: EndpointAppLocation = useLocation(); - const dispatch: (action: AppAction) => unknown = useDispatch(); - dispatch({ type: 'userChangedUrl', payload: location }); - return <>{children}; -}); - interface RouterProps { basename: string; store: Store; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/alert_list.test.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/alert_list.test.ts index 6ba7a34ae81d1..0aeeb6881ad96 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/alert_list.test.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/alert_list.test.ts @@ -14,6 +14,7 @@ import { coreMock } from 'src/core/public/mocks'; import { AlertResultList } from '../../../../../common/types'; import { isOnAlertPage } from './selectors'; import { createBrowserHistory } from 'history'; +import { mockAlertResultList } from './mock_alert_result_list'; describe('alert list tests', () => { let store: Store; @@ -28,37 +29,7 @@ describe('alert list tests', () => { describe('when the user navigates to the alert list page', () => { beforeEach(() => { coreStart.http.get.mockImplementation(async () => { - const response: AlertResultList = { - alerts: [ - { - '@timestamp': new Date(1542341895000), - agent: { - id: 'ced9c68e-b94a-4d66-bb4c-6106514f0a2f', - version: '3.0.0', - }, - event: { - action: 'open', - }, - file_classification: { - malware_classification: { - score: 3, - }, - }, - host: { - hostname: 'HD-c15-bc09190a', - ip: '10.179.244.14', - os: { - name: 'Windows', - }, - }, - thread: {}, - }, - ], - total: 1, - request_page_size: 10, - request_page_index: 0, - result_from_index: 0, - }; + const response: AlertResultList = mockAlertResultList(); return response; }); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/alert_list_pagination.test.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/alert_list_pagination.test.ts index 77708a3c77e2b..5c257c3d65fdc 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/alert_list_pagination.test.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/alert_list_pagination.test.ts @@ -7,37 +7,47 @@ import { Store, createStore, applyMiddleware } from 'redux'; import { History } from 'history'; import { alertListReducer } from './reducer'; -import { AlertListState } from '../../types'; +import { AlertListState, AlertingIndexUIQueryParams } from '../../types'; import { alertMiddlewareFactory } from './middleware'; import { AppAction } from '../action'; import { coreMock } from 'src/core/public/mocks'; import { createBrowserHistory } from 'history'; -import { - urlFromNewPageSizeParam, - paginationDataFromUrl, - urlFromNewPageIndexParam, -} from './selectors'; +import { uiQueryParams } from './selectors'; +import { urlFromQueryParams } from '../../view/alerts/url_from_query_params'; describe('alert list pagination', () => { let store: Store; let coreStart: ReturnType; let history: History; + let queryParams: () => AlertingIndexUIQueryParams; + /** + * Update the history with a new `AlertingIndexUIQueryParams` + */ + let historyPush: (params: AlertingIndexUIQueryParams) => void; beforeEach(() => { coreStart = coreMock.createStart(); history = createBrowserHistory(); + const middleware = alertMiddlewareFactory(coreStart); store = createStore(alertListReducer, applyMiddleware(middleware)); + + history.listen(location => { + store.dispatch({ type: 'userChangedUrl', payload: location }); + }); + + queryParams = () => uiQueryParams(store.getState()); + + historyPush = (nextQueryParams: AlertingIndexUIQueryParams): void => { + return history.push(urlFromQueryParams(nextQueryParams)); + }; }); describe('when the user navigates to the alert list page', () => { describe('when a new page size is passed', () => { beforeEach(() => { - const urlPageSizeSelector = urlFromNewPageSizeParam(store.getState()); - history.push(urlPageSizeSelector(1)); - store.dispatch({ type: 'userChangedUrl', payload: history.location }); + historyPush({ ...queryParams(), page_size: '1' }); }); it('should modify the url correctly', () => { - const actualPaginationQuery = paginationDataFromUrl(store.getState()); - expect(actualPaginationQuery).toMatchInlineSnapshot(` + expect(queryParams()).toMatchInlineSnapshot(` Object { "page_size": "1", } @@ -46,13 +56,10 @@ describe('alert list pagination', () => { describe('and then a new page index is passed', () => { beforeEach(() => { - const urlPageIndexSelector = urlFromNewPageIndexParam(store.getState()); - history.push(urlPageIndexSelector(1)); - store.dispatch({ type: 'userChangedUrl', payload: history.location }); + historyPush({ ...queryParams(), page_index: '1' }); }); it('should modify the url in the correct order', () => { - const actualPaginationQuery = paginationDataFromUrl(store.getState()); - expect(actualPaginationQuery).toMatchInlineSnapshot(` + expect(queryParams()).toMatchInlineSnapshot(` Object { "page_index": "1", "page_size": "1", @@ -64,35 +71,15 @@ describe('alert list pagination', () => { describe('when a new page index is passed', () => { beforeEach(() => { - const urlPageIndexSelector = urlFromNewPageIndexParam(store.getState()); - history.push(urlPageIndexSelector(1)); - store.dispatch({ type: 'userChangedUrl', payload: history.location }); + historyPush({ ...queryParams(), page_index: '1' }); }); it('should modify the url correctly', () => { - const actualPaginationQuery = paginationDataFromUrl(store.getState()); - expect(actualPaginationQuery).toMatchInlineSnapshot(` + expect(queryParams()).toMatchInlineSnapshot(` Object { "page_index": "1", } `); }); - - describe('and then a new page size is passed', () => { - beforeEach(() => { - const urlPageSizeSelector = urlFromNewPageSizeParam(store.getState()); - history.push(urlPageSizeSelector(1)); - store.dispatch({ type: 'userChangedUrl', payload: history.location }); - }); - it('should modify the url correctly and reset index to `0`', () => { - const actualPaginationQuery = paginationDataFromUrl(store.getState()); - expect(actualPaginationQuery).toMatchInlineSnapshot(` - Object { - "page_index": "0", - "page_size": "1", - } - `); - }); - }); }); }); }); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/middleware.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/middleware.ts index 059507c8f0658..76a6867418bd8 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/middleware.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/middleware.ts @@ -4,11 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpFetchQuery } from 'kibana/public'; import { AlertResultList } from '../../../../../common/types'; import { AppAction } from '../action'; import { MiddlewareFactory, AlertListState } from '../../types'; -import { isOnAlertPage, paginationDataFromUrl } from './selectors'; +import { isOnAlertPage, apiQueryParams } from './selectors'; export const alertMiddlewareFactory: MiddlewareFactory = coreStart => { return api => next => async (action: AppAction) => { @@ -16,7 +15,7 @@ export const alertMiddlewareFactory: MiddlewareFactory = coreSta const state = api.getState(); if (action.type === 'userChangedUrl' && isOnAlertPage(state)) { const response: AlertResultList = await coreStart.http.get(`/api/endpoint/alerts`, { - query: paginationDataFromUrl(state) as HttpFetchQuery, + query: apiQueryParams(state), }); api.dispatch({ type: 'serverReturnedAlertsData', payload: response }); } diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/mock_alert_result_list.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/mock_alert_result_list.ts new file mode 100644 index 0000000000000..338a1077b58a2 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/mock_alert_result_list.ts @@ -0,0 +1,60 @@ +/* + * 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 { AlertResultList } from '../../../../../common/types'; + +export const mockAlertResultList: (options?: { + total?: number; + request_page_size?: number; + request_page_index?: number; +}) => AlertResultList = (options = {}) => { + const { + total = 1, + request_page_size: requestPageSize = 10, + request_page_index: requestPageIndex = 0, + } = options; + + // Skip any that are before the page we're on + const numberToSkip = requestPageSize * requestPageIndex; + + // total - numberToSkip is the count of non-skipped ones, but return no more than a pageSize, and no less than 0 + const actualCountToReturn = Math.max(Math.min(total - numberToSkip, requestPageSize), 0); + + const alerts = []; + for (let index = 0; index < actualCountToReturn; index++) { + alerts.push({ + '@timestamp': new Date(1542341895000).toString(), + agent: { + id: 'ced9c68e-b94a-4d66-bb4c-6106514f0a2f', + version: '3.0.0', + }, + event: { + action: 'open', + }, + file_classification: { + malware_classification: { + score: 3, + }, + }, + host: { + hostname: 'HD-c15-bc09190a', + ip: '10.179.244.14', + os: { + name: 'Windows', + }, + }, + thread: {}, + }); + } + const mock: AlertResultList = { + alerts, + total, + request_page_size: requestPageSize, + request_page_index: requestPageIndex, + result_from_index: 0, + }; + return mock; +}; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/selectors.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/selectors.ts index 6ad053888729c..3a0461e06538f 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/selectors.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/selectors.ts @@ -4,9 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -import qs from 'querystring'; -import { AlertListState } from '../../types'; +import querystring from 'querystring'; +import { + createSelector, + createStructuredSelector as createStructuredSelectorWithBadType, +} from 'reselect'; +import { Immutable } from '../../../../../common/types'; +import { + AlertListState, + AlertingIndexUIQueryParams, + AlertsAPIQueryParams, + CreateStructuredSelector, +} from '../../types'; +const createStructuredSelector: CreateStructuredSelector = createStructuredSelectorWithBadType; /** * Returns the Alert Data array from state */ @@ -15,14 +26,12 @@ export const alertListData = (state: AlertListState) => state.alerts; /** * Returns the alert list pagination data from state */ -export const alertListPagination = (state: AlertListState) => { - return { - pageIndex: state.request_page_index, - pageSize: state.request_page_size, - resultFromIndex: state.result_from_index, - total: state.total, - }; -}; +export const alertListPagination = createStructuredSelector({ + pageIndex: (state: AlertListState) => state.request_page_index, + pageSize: (state: AlertListState) => state.request_page_size, + resultFromIndex: (state: AlertListState) => state.result_from_index, + total: (state: AlertListState) => state.total, +}); /** * Returns a boolean based on whether or not the user is on the alerts page @@ -32,48 +41,55 @@ export const isOnAlertPage = (state: AlertListState): boolean => { }; /** - * Returns the query object received from parsing the URL query params - */ -export const paginationDataFromUrl = (state: AlertListState): qs.ParsedUrlQuery => { - if (state.location) { - // Removes the `?` from the beginning of query string if it exists - const query = qs.parse(state.location.search.slice(1)); - return { - ...(query.page_size ? { page_size: query.page_size } : {}), - ...(query.page_index ? { page_index: query.page_index } : {}), - }; - } else { - return {}; - } -}; - -/** - * Returns a function that takes in a new page size and returns a new query param string + * Returns the query object received from parsing the browsers URL query params. + * Used to calculate urls for links and such. */ -export const urlFromNewPageSizeParam: ( +export const uiQueryParams: ( state: AlertListState -) => (newPageSize: number) => string = state => { - return newPageSize => { - const urlPaginationData = paginationDataFromUrl(state); - urlPaginationData.page_size = newPageSize.toString(); +) => Immutable = createSelector( + (state: AlertListState) => state.location, + (location: AlertListState['location']) => { + const data: AlertingIndexUIQueryParams = {}; + if (location) { + // Removes the `?` from the beginning of query string if it exists + const query = querystring.parse(location.search.slice(1)); - // Only set the url back to page zero if the user has changed the page index already - if (urlPaginationData.page_index !== undefined) { - urlPaginationData.page_index = '0'; + /** + * Build an AlertingIndexUIQueryParams object with keys from the query. + * If more than one value exists for a key, use the last. + */ + const keys: Array = [ + 'page_size', + 'page_index', + 'selected_alert', + ]; + for (const key of keys) { + const value = query[key]; + if (typeof value === 'string') { + data[key] = value; + } else if (Array.isArray(value)) { + data[key] = value[value.length - 1]; + } + } } - return '?' + qs.stringify(urlPaginationData); - }; -}; + return data; + } +); /** - * Returns a function that takes in a new page index and returns a new query param string + * query params to use when requesting alert data. */ -export const urlFromNewPageIndexParam: ( +export const apiQueryParams: ( state: AlertListState -) => (newPageIndex: number) => string = state => { - return newPageIndex => { - const urlPaginationData = paginationDataFromUrl(state); - urlPaginationData.page_index = newPageIndex.toString(); - return '?' + qs.stringify(urlPaginationData); - }; -}; +) => Immutable = createSelector( + uiQueryParams, + ({ page_size, page_index }) => ({ + page_size, + page_index, + }) +); + +export const hasSelectedAlert: (state: AlertListState) => boolean = createSelector( + uiQueryParams, + ({ selected_alert: selectedAlert }) => selectedAlert !== undefined +); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/index.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/index.ts index 3aeeeaf1c09e2..b95ff7cb2d45c 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/index.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/index.ts @@ -48,25 +48,36 @@ export const substateMiddlewareFactory = ( }; }; -export const appStoreFactory = (coreStart: CoreStart): Store => { +export const appStoreFactory: ( + /** + * Allow middleware to communicate with Kibana core. + */ + coreStart: CoreStart, + /** + * Create the store without any middleware. This is useful for testing the store w/o side effects. + */ + disableMiddleware?: boolean +) => Store = (coreStart, disableMiddleware = false) => { const store = createStore( appReducer, - composeWithReduxDevTools( - applyMiddleware( - substateMiddlewareFactory( - globalState => globalState.managementList, - managementMiddlewareFactory(coreStart) - ), - substateMiddlewareFactory( - globalState => globalState.policyList, - policyListMiddlewareFactory(coreStart) - ), - substateMiddlewareFactory( - globalState => globalState.alertList, - alertMiddlewareFactory(coreStart) + disableMiddleware + ? undefined + : composeWithReduxDevTools( + applyMiddleware( + substateMiddlewareFactory( + globalState => globalState.managementList, + managementMiddlewareFactory(coreStart) + ), + substateMiddlewareFactory( + globalState => globalState.policyList, + policyListMiddlewareFactory(coreStart) + ), + substateMiddlewareFactory( + globalState => globalState.alertList, + alertMiddlewareFactory(coreStart) + ) + ) ) - ) - ) ); return store; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts index d07521d09a119..bd4838419891d 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts @@ -10,6 +10,7 @@ import { EndpointMetadata } from '../../../common/types'; import { AppAction } from './store/action'; import { AlertResultList, Immutable } from '../../../common/types'; +export { AppAction }; export type MiddlewareFactory = ( coreStart: CoreStart ) => ( @@ -63,6 +64,9 @@ export interface GlobalState { readonly policyList: PolicyListState; } +/** + * A better type for createStructuredSelector. This doesn't support the options object. + */ export type CreateStructuredSelector = < SelectorMap extends { [key: string]: (...args: never[]) => unknown } >( @@ -76,7 +80,6 @@ export type CreateStructuredSelector = < export interface EndpointAppLocation { pathname: string; search: string; - state: never; hash: string; key?: string; } @@ -85,3 +88,35 @@ export type AlertListData = AlertResultList; export type AlertListState = Immutable & { readonly location?: Immutable; }; + +/** + * Gotten by parsing the URL from the browser. Used to calculate the new URL when changing views. + */ +export interface AlertingIndexUIQueryParams { + /** + * How many items to show in list. + */ + page_size?: string; + /** + * Which page to show. If `page_index` is 1, show page 2. + */ + page_index?: string; + /** + * If any value is present, show the alert detail view for the selected alert. Should be an ID for an alert event. + */ + selected_alert?: string; +} + +/** + * Query params to pass to the alert API when fetching new data. + */ +export interface AlertsAPIQueryParams { + /** + * Number of results to return. + */ + page_size?: string; + /** + * 0-based index of 'page' to return. + */ + page_index?: string; +} diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/alerts/index.test.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/alerts/index.test.tsx new file mode 100644 index 0000000000000..37847553d512a --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/alerts/index.test.tsx @@ -0,0 +1,189 @@ +/* + * 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 * as reactTestingLibrary from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { I18nProvider } from '@kbn/i18n/react'; +import { AlertIndex } from './index'; +import { appStoreFactory } from '../../store'; +import { coreMock } from 'src/core/public/mocks'; +import { fireEvent, waitForElement, act } from '@testing-library/react'; +import { RouteCapture } from '../route_capture'; +import { createMemoryHistory, MemoryHistory } from 'history'; +import { Router } from 'react-router-dom'; +import { AppAction } from '../../types'; +import { mockAlertResultList } from '../../store/alerts/mock_alert_result_list'; + +describe('when on the alerting page', () => { + let render: () => reactTestingLibrary.RenderResult; + let history: MemoryHistory; + let store: ReturnType; + + /** + * @testing-library/react provides `queryByTestId`, but that uses the data attribute + * 'data-testid' whereas our FTR and EUI's tests all use 'data-test-subj'. While @testing-library/react + * could be configured to use 'data-test-subj', it is not currently configured that way. + * + * This provides an equivalent function to `queryByTestId` but that uses our 'data-test-subj' attribute. + */ + let queryByTestSubjId: ( + renderResult: reactTestingLibrary.RenderResult, + testSubjId: string + ) => Promise; + + beforeEach(async () => { + /** + * Create a 'history' instance that is only in-memory and causes no side effects to the testing environment. + */ + history = createMemoryHistory(); + /** + * Create a store, with the middleware disabled. We don't want side effects being created by our code in this test. + */ + store = appStoreFactory(coreMock.createStart(), true); + /** + * Render the test component, use this after setting up anything in `beforeEach`. + */ + render = () => { + /** + * Provide the store via `Provider`, and i18n APIs via `I18nProvider`. + * Use react-router via `Router`, passing our in-memory `history` instance. + * Use `RouteCapture` to emit url-change actions when the URL is changed. + * Finally, render the `AlertIndex` component which we are testing. + */ + return reactTestingLibrary.render( + + + + + + + + + + ); + }; + queryByTestSubjId = async (renderResult, testSubjId) => { + return await waitForElement( + /** + * Use document.body instead of container because EUI renders things like popover out of the DOM heirarchy. + */ + () => document.body.querySelector(`[data-test-subj="${testSubjId}"]`), + { + container: renderResult.container, + } + ); + }; + }); + it('should show a data grid', async () => { + await render().findByTestId('alertListGrid'); + }); + describe('when there is no selected alert in the url', () => { + it('should not show the flyout', () => { + expect(render().queryByTestId('alertDetailFlyout')).toBeNull(); + }); + describe('when data loads', () => { + beforeEach(() => { + /** + * Dispatch the `serverReturnedAlertsData` action, which is normally dispatched by the middleware + * after interacting with the server. + */ + reactTestingLibrary.act(() => { + const action: AppAction = { + type: 'serverReturnedAlertsData', + payload: mockAlertResultList(), + }; + store.dispatch(action); + }); + }); + it('should render the alert summary row in the grid', async () => { + const renderResult = render(); + const rows = await renderResult.findAllByRole('row'); + + /** + * There should be a 'row' which is the header, and + * row which is the alert item. + */ + expect(rows).toHaveLength(2); + }); + describe('when the user has clicked the alert type in the grid', () => { + let renderResult: reactTestingLibrary.RenderResult; + beforeEach(async () => { + renderResult = render(); + /** + * This is the cell with the alert type, it has a link. + */ + fireEvent.click(await renderResult.findByTestId('alertTypeCellLink')); + }); + it('should show the flyout', async () => { + await renderResult.findByTestId('alertDetailFlyout'); + }); + }); + }); + }); + describe('when there is a selected alert in the url', () => { + beforeEach(() => { + reactTestingLibrary.act(() => { + history.push({ + ...history.location, + search: '?selected_alert=1', + }); + }); + }); + it('should show the flyout', async () => { + await render().findByTestId('alertDetailFlyout'); + }); + describe('when the user clicks the close button on the flyout', () => { + let renderResult: reactTestingLibrary.RenderResult; + beforeEach(async () => { + renderResult = render(); + /** + * Use our helper function to find the flyout's close button, as it uses a different test ID attribute. + */ + const closeButton = await queryByTestSubjId(renderResult, 'euiFlyoutCloseButton'); + if (closeButton) { + fireEvent.click(closeButton); + } + }); + it('should no longer show the flyout', () => { + expect(render().queryByTestId('alertDetailFlyout')).toBeNull(); + }); + }); + }); + describe('when the url has page_size=1 and a page_index=1', () => { + beforeEach(() => { + reactTestingLibrary.act(() => { + history.push({ + ...history.location, + search: '?page_size=1&page_index=1', + }); + }); + }); + describe('when the user changes page size to 10', () => { + beforeEach(async () => { + const renderResult = render(); + const paginationButton = await queryByTestSubjId( + renderResult, + 'tablePaginationPopoverButton' + ); + if (paginationButton) { + act(() => { + fireEvent.click(paginationButton); + }); + } + const show10RowsButton = await queryByTestSubjId(renderResult, 'tablePagination-10-rows'); + if (show10RowsButton) { + act(() => { + fireEvent.click(show10RowsButton); + }); + } + }); + it('should have a page_index of 0', () => { + expect(history.location.search).toBe('?page_size=10'); + }); + }); + }); +}); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/alerts/index.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/alerts/index.tsx index 045b82200b11b..6f88727575557 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/alerts/index.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/alerts/index.tsx @@ -6,16 +6,30 @@ import { memo, useState, useMemo, useCallback } from 'react'; import React from 'react'; -import { EuiDataGrid, EuiDataGridColumn, EuiPage, EuiPageBody, EuiPageContent } from '@elastic/eui'; +import { + EuiDataGrid, + EuiDataGridColumn, + EuiPage, + EuiPageBody, + EuiPageContent, + EuiFlyout, + EuiFlyoutHeader, + EuiFlyoutBody, + EuiTitle, + EuiBadge, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { useHistory } from 'react-router-dom'; +import { useHistory, Link } from 'react-router-dom'; +import { FormattedDate } from 'react-intl'; +import { urlFromQueryParams } from './url_from_query_params'; +import { AlertData } from '../../../../../common/types'; import * as selectors from '../../store/alerts/selectors'; import { useAlertListSelector } from './hooks/use_alerts_selector'; export const AlertIndex = memo(() => { const history = useHistory(); - const columns: EuiDataGridColumn[] = useMemo(() => { + const columns = useMemo((): EuiDataGridColumn[] => { return [ { id: 'alert_type', @@ -69,22 +83,48 @@ export const AlertIndex = memo(() => { }, []); const { pageIndex, pageSize, total } = useAlertListSelector(selectors.alertListPagination); - const urlFromNewPageSizeParam = useAlertListSelector(selectors.urlFromNewPageSizeParam); - const urlFromNewPageIndexParam = useAlertListSelector(selectors.urlFromNewPageIndexParam); const alertListData = useAlertListSelector(selectors.alertListData); + const hasSelectedAlert = useAlertListSelector(selectors.hasSelectedAlert); + const queryParams = useAlertListSelector(selectors.uiQueryParams); const onChangeItemsPerPage = useCallback( - newPageSize => history.push(urlFromNewPageSizeParam(newPageSize)), - [history, urlFromNewPageSizeParam] + newPageSize => { + const newQueryParms = { ...queryParams }; + newQueryParms.page_size = newPageSize; + delete newQueryParms.page_index; + const relativeURL = urlFromQueryParams(newQueryParms); + return history.push(relativeURL); + }, + [history, queryParams] ); const onChangePage = useCallback( - newPageIndex => history.push(urlFromNewPageIndexParam(newPageIndex)), - [history, urlFromNewPageIndexParam] + newPageIndex => { + return history.push( + urlFromQueryParams({ + ...queryParams, + page_index: newPageIndex, + }) + ); + }, + [history, queryParams] ); const [visibleColumns, setVisibleColumns] = useState(() => columns.map(({ id }) => id)); + const handleFlyoutClose = useCallback(() => { + const { selected_alert, ...paramsWithoutSelectedAlert } = queryParams; + history.push(urlFromQueryParams(paramsWithoutSelectedAlert)); + }, [history, queryParams]); + + const datesForRows: Map = useMemo(() => { + return new Map( + alertListData.map(alertData => { + return [alertData, new Date(alertData['@timestamp'])]; + }) + ); + }, [alertListData]); + const renderCellValue = useMemo(() => { return ({ rowIndex, columnId }: { rowIndex: number; columnId: string }) => { if (rowIndex > total) { @@ -94,11 +134,18 @@ export const AlertIndex = memo(() => { const row = alertListData[rowIndex % pageSize]; if (columnId === 'alert_type') { - return i18n.translate( - 'xpack.endpoint.application.endpoint.alerts.alertType.maliciousFileDescription', - { - defaultMessage: 'Malicious File', - } + return ( + + {i18n.translate( + 'xpack.endpoint.application.endpoint.alerts.alertType.maliciousFileDescription', + { + defaultMessage: 'Malicious File', + } + )} + ); } else if (columnId === 'event_type') { return row.event.action; @@ -109,7 +156,31 @@ export const AlertIndex = memo(() => { } else if (columnId === 'host_name') { return row.host.hostname; } else if (columnId === 'timestamp') { - return row['@timestamp']; + const date = datesForRows.get(row)!; + if (date && isFinite(date.getTime())) { + return ( + + ); + } else { + return ( + + {i18n.translate( + 'xpack.endpoint.application.endpoint.alerts.alertDate.timestampInvalidLabel', + { + defaultMessage: 'invalid', + } + )} + + ); + } } else if (columnId === 'archived') { return null; } else if (columnId === 'malware_score') { @@ -117,7 +188,7 @@ export const AlertIndex = memo(() => { } return null; }; - }, [alertListData, pageSize, total]); + }, [alertListData, datesForRows, pageSize, queryParams, total]); const pagination = useMemo(() => { return { @@ -130,23 +201,43 @@ export const AlertIndex = memo(() => { }, [onChangeItemsPerPage, onChangePage, pageIndex, pageSize]); return ( - - - - - - - + <> + {hasSelectedAlert && ( + + + +

+ {i18n.translate('xpack.endpoint.application.endpoint.alerts.detailsTitle', { + defaultMessage: 'Alert Details', + })} +

+
+
+ +
+ )} + + + + ({ + visibleColumns, + setVisibleColumns, + }), + [setVisibleColumns, visibleColumns] + )} + renderCellValue={renderCellValue} + pagination={pagination} + data-test-subj="alertListGrid" + data-testid="alertListGrid" + /> + + + + ); }); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/alerts/url_from_query_params.ts b/x-pack/plugins/endpoint/public/applications/endpoint/view/alerts/url_from_query_params.ts new file mode 100644 index 0000000000000..e037d000e6e8f --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/alerts/url_from_query_params.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import querystring from 'querystring'; +import { AlertingIndexUIQueryParams, EndpointAppLocation } from '../../types'; + +/** + * Return a relative URL for `AlertingIndexUIQueryParams`. + * usage: + * + * ```ts + * // Replace this with however you get state, e.g. useSelector in react + * const queryParams = selectors.uiQueryParams(store.getState()) + * + * // same as current url, but page_index is now 3 + * const relativeURL = urlFromQueryParams({ ...queryParams, page_index: 3 }) + * + * // now use relativeURL in the 'href' of a link, the 'to' of a react-router-dom 'Link' or history.push, history.replace + * ``` + */ +export function urlFromQueryParams( + queryParams: AlertingIndexUIQueryParams +): Partial { + const search = querystring.stringify(queryParams); + return { + search, + }; +} diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/route_capture.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/route_capture.tsx new file mode 100644 index 0000000000000..28d2019b56888 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/route_capture.tsx @@ -0,0 +1,21 @@ +/* + * 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, { memo } from 'react'; +import { useLocation } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; +import { EndpointAppLocation, AppAction } from '../types'; + +/** + * This component should be used above all routes, but below the Provider. + * It dispatches actions when the URL is changed. + */ +export const RouteCapture = memo(({ children }) => { + const location: EndpointAppLocation = useLocation(); + const dispatch: (action: AppAction) => unknown = useDispatch(); + dispatch({ type: 'userChangedUrl', payload: location }); + return <>{children}; +}); diff --git a/x-pack/plugins/endpoint/public/embeddables/resolver/store/selectors.ts b/x-pack/plugins/endpoint/public/embeddables/resolver/store/selectors.ts index 4d12e656205fa..25d08a8c347ed 100644 --- a/x-pack/plugins/endpoint/public/embeddables/resolver/store/selectors.ts +++ b/x-pack/plugins/endpoint/public/embeddables/resolver/store/selectors.ts @@ -31,7 +31,6 @@ export const inverseProjectionMatrix = composeSelectors( /** * The scale by which world values are scaled when rendered. - * TODO make it a number */ export const scale = composeSelectors(cameraStateSelector, cameraSelectors.scale); diff --git a/x-pack/plugins/endpoint/public/embeddables/resolver/view/use_camera.test.tsx b/x-pack/plugins/endpoint/public/embeddables/resolver/view/use_camera.test.tsx index 85e1d4e694b15..f4abb51f062f2 100644 --- a/x-pack/plugins/endpoint/public/embeddables/resolver/view/use_camera.test.tsx +++ b/x-pack/plugins/endpoint/public/embeddables/resolver/view/use_camera.test.tsx @@ -4,9 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -/** - * This import must be hoisted as it uses `jest.mock`. Is there a better way? Mocking is not good. - */ import React from 'react'; import { render, act, RenderResult, fireEvent } from '@testing-library/react'; import { useCamera } from './use_camera'; diff --git a/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.test.ts b/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.test.ts index a4d7de8fdcfdb..3ef1142b9ce46 100644 --- a/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.test.ts +++ b/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.test.ts @@ -16,26 +16,36 @@ describe('test query builder', () => { config: () => Promise.resolve(EndpointConfigSchema.validate({})), }; const queryParams = await getPagingProperties(mockRequest, mockCtx); - const query = await buildAlertListESQuery(queryParams); + const query = buildAlertListESQuery(queryParams); - expect(query).toEqual({ - body: { - query: { - match_all: {}, - }, - sort: [ - { - '@timestamp': { - order: 'desc', + expect(query).toMatchInlineSnapshot(` + Object { + "body": Object { + "query": Object { + "bool": Object { + "must": Array [ + Object { + "match": Object { + "event.kind": "alert", + }, + }, + ], }, }, - ], - track_total_hits: 10000, - }, - from: 0, - size: 10, - index: 'my-index', - } as Record); + "sort": Array [ + Object { + "@timestamp": Object { + "order": "desc", + }, + }, + ], + "track_total_hits": 10000, + }, + "from": 0, + "index": "my-index", + "size": 10, + } + `); }); it('should adjust track_total_hits for deep pagination', async () => { const mockRequest = httpServerMock.createKibanaRequest({ @@ -49,26 +59,36 @@ describe('test query builder', () => { config: () => Promise.resolve(EndpointConfigSchema.validate({})), }; const queryParams = await getPagingProperties(mockRequest, mockCtx); - const query = await buildAlertListESQuery(queryParams); + const query = buildAlertListESQuery(queryParams); - expect(query).toEqual({ - body: { - query: { - match_all: {}, - }, - sort: [ - { - '@timestamp': { - order: 'desc', + expect(query).toMatchInlineSnapshot(` + Object { + "body": Object { + "query": Object { + "bool": Object { + "must": Array [ + Object { + "match": Object { + "event.kind": "alert", + }, + }, + ], }, }, - ], - track_total_hits: 12000, - }, - from: 10000, - size: 1000, - index: 'my-index', - } as Record); + "sort": Array [ + Object { + "@timestamp": Object { + "order": "desc", + }, + }, + ], + "track_total_hits": 12000, + }, + "from": 10000, + "index": "my-index", + "size": 1000, + } + `); }); }); }); diff --git a/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.ts b/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.ts index a20f2ae1cdecd..e56ae43ef5c76 100644 --- a/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.ts +++ b/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.ts @@ -7,9 +7,9 @@ import { KibanaRequest } from 'kibana/server'; import { EndpointAppConstants } from '../../../common/types'; import { EndpointAppContext, AlertRequestParams, JSONish } from '../../types'; -export const buildAlertListESQuery = async ( +export const buildAlertListESQuery: ( pagingProperties: Record -): Promise => { +) => JSONish = pagingProperties => { const DEFAULT_TOTAL_HITS = 10000; // Calculate minimum total hits set to indicate there's a next page @@ -22,7 +22,15 @@ export const buildAlertListESQuery = async ( body: { track_total_hits: totalHitsMin, query: { - match_all: {}, + bool: { + must: [ + { + match: { + 'event.kind': 'alert', + }, + }, + ], + }, }, sort: [ { From 8ccbe87069416da68feb87b411fcb6292d3456c5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2020 14:49:48 -0600 Subject: [PATCH 012/123] Update dependency @elastic/charts to ^17.1.1 (#57634) --- package.json | 2 +- packages/kbn-ui-shared-deps/package.json | 2 +- yarn.lock | 59 +++++------------------- 3 files changed, 13 insertions(+), 50 deletions(-) diff --git a/package.json b/package.json index cb87c48ab7f2a..c3fe290e7934f 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "@babel/core": "^7.5.5", "@babel/register": "^7.7.0", "@elastic/apm-rum": "^4.6.0", - "@elastic/charts": "^17.0.2", + "@elastic/charts": "^17.1.1", "@elastic/datemath": "5.0.2", "@elastic/ems-client": "7.6.0", "@elastic/eui": "19.0.0", diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index acb2b48e12278..e9ad227b235fa 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -9,7 +9,7 @@ "kbn:watch": "node scripts/build --watch" }, "devDependencies": { - "@elastic/charts": "^17.0.2", + "@elastic/charts": "^17.1.1", "abortcontroller-polyfill": "^1.4.0", "@elastic/eui": "19.0.0", "@kbn/babel-preset": "1.0.0", diff --git a/yarn.lock b/yarn.lock index 2caaac974dfad..8ea23c17b8b8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1680,7 +1680,7 @@ dependencies: regenerator-runtime "^0.13.2" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2": version "7.7.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.6.tgz#d18c511121aff1b4f2cd1d452f1bac9601dd830f" integrity sha512-BWAJxpNVa0QlE5gZdWjSxXtemZyZ9RmrmVozxt3NUXeZhVIJ5ANyqmMc0JDrivBZyxUuQvFxlvH4OWWOogGfUw== @@ -1880,10 +1880,10 @@ dependencies: "@elastic/apm-rum-core" "^4.7.0" -"@elastic/charts@^17.0.2": - version "17.0.2" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-17.0.2.tgz#0bd2cb7b78bd60255eed2a9b0ce5049a62dc5d8a" - integrity sha512-hz31Yma/HSdu9tRS/05xNXY+YuaHOadD9Gd+eh7ankNlJJOFI4IRV6F8BMnloeWYedNXBSTp4susFLwJNQQ+0w== +"@elastic/charts@^17.1.1": + version "17.1.1" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-17.1.1.tgz#28df3d1be445aa4951fac59dec0831760a1ea034" + integrity sha512-zI3ZHy51tqlsEenDbHFWlL6qbDMvrQXeuV+UFleILtVcfI0r4Lk7DtSbx4GQlHcBuVvvAk1MRdYKNGA0IYWP6w== dependencies: "@types/d3-shape" "^1.3.1" classnames "^2.2.6" @@ -1892,14 +1892,11 @@ d3-color "^1.4.0" d3-scale "^1.0.7" d3-shape "^1.3.4" - fast-deep-equal "^3.1.1" - konva "^4.0.18" newtype-ts "^0.2.4" + path2d-polyfill "^0.4.2" prop-types "^15.7.2" re-reselect "^3.4.0" - react-konva "16.10.1-0" react-redux "^7.1.0" - react-spring "^8.0.8" redux "^4.0.4" reselect "^4.0.0" resize-observer-polyfill "^1.5.1" @@ -19008,11 +19005,6 @@ known-css-properties@^0.3.0: resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.3.0.tgz#a3d135bbfc60ee8c6eacf2f7e7e6f2d4755e49a4" integrity sha512-QMQcnKAiQccfQTqtBh/qwquGZ2XK/DXND1jrcN9M8gMMy99Gwla7GQjndVUsEqIaRyP6bsFRuhwRj5poafBGJQ== -konva@^4.0.18: - version "4.0.18" - resolved "https://registry.yarnpkg.com/konva/-/konva-4.0.18.tgz#43e614c9b22827183506d4a6b3b474f90187b469" - integrity sha512-Tlq0v7QHr8q73xr1cKjHdQl41oHC06IOldPO+ukjt99G74NgoU0TVouvPIFpW2whA9t3xNk/+/VJcc3XPcboOw== - kopy@^8.2.0: version "8.2.5" resolved "https://registry.yarnpkg.com/kopy/-/kopy-8.2.5.tgz#6c95f312e981ab917680d7e5de3cdf29a1bf221f" @@ -22917,6 +22909,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +path2d-polyfill@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/path2d-polyfill/-/path2d-polyfill-0.4.2.tgz#594d3103838ef6b9dd4a7fd498fe9a88f1f28531" + integrity sha512-JSeAnUfkFjl+Ml/EZL898ivMSbGHrOH63Mirx5EQ1ycJiryHDmj1Q7Are+uEPvenVGCUN9YbolfGfyUewJfJEg== + pathval@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" @@ -24504,14 +24501,6 @@ react-is@~16.3.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.2.tgz#f4d3d0e2f5fbb6ac46450641eb2e25bf05d36b22" integrity sha512-ybEM7YOr4yBgFd6w8dJqwxegqZGJNBZl6U27HnGKuTZmDvVrD5quWOK/wAnMywiZzW+Qsk+l4X2c70+thp/A8Q== -react-konva@16.10.1-0: - version "16.10.1-0" - resolved "https://registry.yarnpkg.com/react-konva/-/react-konva-16.10.1-0.tgz#f8cc2c95374933069e891a6c714c70d0fdc77e68" - integrity sha512-N0Zi3TcWmUxb2d7y1DUDQhRA+WIcqk54DQmmUmJSadj+fS0bg6iZDebQSEQC8dMbjnLHc/338xRT4a4718PEiw== - dependencies: - react-reconciler "^0.22.1" - scheduler "^0.16.1" - react-lib-adler32@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/react-lib-adler32/-/react-lib-adler32-1.0.3.tgz#63df1aed274eabcc1c5067077ea281ec30888ba7" @@ -24647,16 +24636,6 @@ react-portal@^3.2.0: dependencies: prop-types "^15.5.8" -react-reconciler@^0.22.1: - version "0.22.2" - resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.22.2.tgz#e8a10374fec8fee7c5cd0cf3cd05626f1b134d3e" - integrity sha512-MLX5Y2pNLsdXzWz/GLNhhYkdLOvxEtw2IGqVCzkiRdSFSHRjujI9gfTOQ3rV5z8toTBxSZ2qrRkRUo97mmEdhA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.16.2" - react-redux@^5.0.7, react-redux@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.1.2.tgz#b19cf9e21d694422727bf798e934a916c4080f57" @@ -24798,14 +24777,6 @@ react-sizeme@^2.6.7: shallowequal "^1.1.0" throttle-debounce "^2.1.0" -react-spring@^8.0.8: - version "8.0.20" - resolved "https://registry.yarnpkg.com/react-spring/-/react-spring-8.0.20.tgz#e25967f6059364b09cf0339168d73014e87c9d17" - integrity sha512-40ZUQ5uI5YHsoQWLPchWNcEUh6zQ6qvcVDeTI2vW10ldoCN3PvDsII9wBH2xEbMl+BQvYmHzGdfLTQxPxJWGnQ== - dependencies: - "@babel/runtime" "^7.3.1" - prop-types "^15.5.8" - react-sticky@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/react-sticky/-/react-sticky-6.0.3.tgz#7a18b643e1863da113d7f7036118d2a75d9ecde4" @@ -26570,14 +26541,6 @@ saxes@^3.1.9: dependencies: xmlchars "^2.1.1" -scheduler@^0.16.1, scheduler@^0.16.2: - version "0.16.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.16.2.tgz#f74cd9d33eff6fc554edfb79864868e4819132c1" - integrity sha512-BqYVWqwz6s1wZMhjFvLfVR5WXP7ZY32M/wYPo04CcuPM7XZEbV2TBNW7Z0UkguPTl0dWMA59VbNXxK6q+pHItg== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler@^0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4" From d61ef267d530554cd048b5e602a0b6c2e362185f Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Fri, 21 Feb 2020 22:11:05 +0100 Subject: [PATCH 013/123] force savedObject API consumers to define SO type explicitly (#58022) * force savedObject consumers to define type explicitly * address comments * regen docs --- .../kibana-plugin-public.savedobject.md | 2 +- ...plugin-public.savedobjectsbatchresponse.md | 2 +- ...gin-public.savedobjectsbulkcreateobject.md | 2 +- ...gin-public.savedobjectsbulkupdateobject.md | 2 +- ...in-public.savedobjectsclient.bulkcreate.md | 2 +- ...lugin-public.savedobjectsclient.bulkget.md | 2 +- ...in-public.savedobjectsclient.bulkupdate.md | 4 +- ...plugin-public.savedobjectsclient.create.md | 2 +- ...a-plugin-public.savedobjectsclient.find.md | 2 +- ...na-plugin-public.savedobjectsclient.get.md | 2 +- ...kibana-plugin-public.savedobjectsclient.md | 10 ++--- ...plugin-public.savedobjectsclient.update.md | 2 +- ...n-public.savedobjectsfindresponsepublic.md | 2 +- .../kibana-plugin-public.simplesavedobject.md | 2 +- .../kibana-plugin-server.savedobject.md | 2 +- ...gin-server.savedobjectsbulkcreateobject.md | 2 +- ...-plugin-server.savedobjectsbulkresponse.md | 2 +- ...gin-server.savedobjectsbulkupdateobject.md | 2 +- ...n-server.savedobjectsbulkupdateresponse.md | 2 +- ...in-server.savedobjectsclient.bulkcreate.md | 2 +- ...lugin-server.savedobjectsclient.bulkget.md | 2 +- ...in-server.savedobjectsclient.bulkupdate.md | 2 +- ...plugin-server.savedobjectsclient.create.md | 2 +- ...a-plugin-server.savedobjectsclient.find.md | 2 +- ...na-plugin-server.savedobjectsclient.get.md | 2 +- ...plugin-server.savedobjectsclient.update.md | 2 +- ...-plugin-server.savedobjectsfindresponse.md | 2 +- ...erver.savedobjectsrepository.bulkcreate.md | 2 +- ...n-server.savedobjectsrepository.bulkget.md | 2 +- ...erver.savedobjectsrepository.bulkupdate.md | 2 +- ...in-server.savedobjectsrepository.create.md | 2 +- ...ugin-server.savedobjectsrepository.find.md | 2 +- ...lugin-server.savedobjectsrepository.get.md | 2 +- ...in-server.savedobjectsrepository.update.md | 2 +- ...lugin-server.savedobjectsupdateresponse.md | 2 +- src/core/public/public.api.md | 26 +++++------ .../saved_objects/saved_objects_client.ts | 36 +++++---------- .../saved_objects/simple_saved_object.ts | 6 +-- .../import/collect_saved_objects.ts | 4 +- .../saved_objects/import/extract_errors.ts | 7 +-- .../import/validate_references.ts | 2 +- .../saved_objects/management/management.ts | 6 +-- .../saved_objects/serialization/types.ts | 2 +- .../saved_objects/service/lib/repository.ts | 19 ++++---- .../service/saved_objects_client.ts | 35 ++++++--------- src/core/server/saved_objects/types.ts | 3 +- src/core/server/server.api.md | 44 +++++++++---------- .../create_or_upgrade_saved_config.ts | 5 ++- .../server/ui_settings/ui_settings_client.ts | 2 +- .../discover_index_pattern.test.tsx | 4 +- .../field_chooser/discover_index_pattern.tsx | 5 ++- .../step_index_pattern/step_index_pattern.tsx | 3 +- .../public/helpers/arg_value_suggestions.ts | 9 ++-- .../public/embeddable/get_index_pattern.ts | 13 ++++-- .../data/common/index_patterns/types.ts | 12 +++++ src/plugins/data/public/index.ts | 1 + .../index_patterns/index_patterns.ts | 2 +- .../lib/get_from_saved_object.ts | 9 ++-- .../fetch_index_patterns.ts | 11 +++-- src/plugins/data/server/index.ts | 1 + .../lib/sample_dataset_registry_types.ts | 4 +- .../sample_data/sample_data_registry.ts | 4 +- .../public/finder/saved_object_finder.tsx | 31 +++++++------ .../saved_object/saved_object_loader.ts | 2 +- .../routes/lib/short_url_lookup.test.ts | 28 +++++------- .../server/routes/lib/short_url_lookup.ts | 15 +++++-- .../plugins/canvas/public/lib/es_service.ts | 6 ++- .../persistence/saved_workspace_loader.ts | 2 +- .../legacy/plugins/ml/common/types/kibana.ts | 8 ++-- .../jobs/new_job/recognize/resolvers.ts | 2 +- .../ml/public/application/util/index_utils.ts | 5 ++- .../models/data_recognizer/data_recognizer.ts | 9 +++- .../models/job_service/new_job_caps/rollup.ts | 5 ++- .../detection_engine/signals/get_filter.ts | 14 +++++- .../signals/get_input_output_index.ts | 4 +- .../signals/signal_rule_alert_type.ts | 30 ++++++++----- .../plugins/task_manager/server/migrations.ts | 4 +- .../transform/public/app/lib/kibana/common.ts | 3 +- .../np_ready/lib/telemetry/usage_collector.ts | 7 ++- .../plugins/actions/server/actions_client.ts | 12 ++--- .../actions/server/create_execute_function.ts | 4 +- .../plugins/alerting/server/alerts_client.ts | 2 +- .../server/task_runner/task_runner.ts | 3 +- .../canvas/server/routes/workpad/update.ts | 3 +- .../case/server/services/tags/read_tags.ts | 2 +- .../encrypted_saved_objects_client_wrapper.ts | 35 +++++++-------- .../server/saved_objects/index.ts | 17 +++---- .../hooks/use_bulk_get_saved_object.tsx | 5 ++- .../server/routes/existing_fields.test.ts | 2 + .../lens/server/routes/existing_fields.ts | 12 +++-- .../secure_saved_objects_client_wrapper.ts | 27 ++++++------ .../spaces_saved_objects_client.ts | 27 ++++++------ .../task_manager/server/task_store.test.ts | 28 +++++------- .../plugins/task_manager/server/task_store.ts | 3 +- .../suites/resolve_copy_to_space_conflicts.ts | 4 +- 95 files changed, 387 insertions(+), 329 deletions(-) diff --git a/docs/development/core/public/kibana-plugin-public.savedobject.md b/docs/development/core/public/kibana-plugin-public.savedobject.md index b1bb3e267bf0e..542d7d3a063ec 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobject.md +++ b/docs/development/core/public/kibana-plugin-public.savedobject.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface SavedObject +export interface SavedObject ``` ## Properties diff --git a/docs/development/core/public/kibana-plugin-public.savedobjectsbatchresponse.md b/docs/development/core/public/kibana-plugin-public.savedobjectsbatchresponse.md index 5a08b3f97f429..97772112ff006 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobjectsbatchresponse.md +++ b/docs/development/core/public/kibana-plugin-public.savedobjectsbatchresponse.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface SavedObjectsBatchResponse +export interface SavedObjectsBatchResponse ``` ## Properties diff --git a/docs/development/core/public/kibana-plugin-public.savedobjectsbulkcreateobject.md b/docs/development/core/public/kibana-plugin-public.savedobjectsbulkcreateobject.md index c479e9f9f3e3f..ef83acb8fd73d 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobjectsbulkcreateobject.md +++ b/docs/development/core/public/kibana-plugin-public.savedobjectsbulkcreateobject.md @@ -7,7 +7,7 @@ Signature: ```typescript -export interface SavedObjectsBulkCreateObject extends SavedObjectsCreateOptions +export interface SavedObjectsBulkCreateObject extends SavedObjectsCreateOptions ``` ## Properties diff --git a/docs/development/core/public/kibana-plugin-public.savedobjectsbulkupdateobject.md b/docs/development/core/public/kibana-plugin-public.savedobjectsbulkupdateobject.md index ca0eabb265901..a57702c305f50 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobjectsbulkupdateobject.md +++ b/docs/development/core/public/kibana-plugin-public.savedobjectsbulkupdateobject.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface SavedObjectsBulkUpdateObject +export interface SavedObjectsBulkUpdateObject ``` ## Properties diff --git a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.bulkcreate.md b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.bulkcreate.md index 391b2f57205d5..c5072bea5b50e 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.bulkcreate.md +++ b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.bulkcreate.md @@ -9,5 +9,5 @@ Creates multiple documents at once Signature: ```typescript -bulkCreate: (objects?: SavedObjectsBulkCreateObject[], options?: SavedObjectsBulkCreateOptions) => Promise>; +bulkCreate: (objects?: SavedObjectsBulkCreateObject[], options?: SavedObjectsBulkCreateOptions) => Promise>; ``` diff --git a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.bulkget.md b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.bulkget.md index a54dfe72167a7..37b9f6d6c951d 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.bulkget.md +++ b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.bulkget.md @@ -12,7 +12,7 @@ Returns an array of objects by id bulkGet: (objects?: { id: string; type: string; - }[]) => Promise>; + }[]) => Promise>; ``` ## Example diff --git a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.bulkupdate.md b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.bulkupdate.md index 94ae9bb70ccda..2f8565def3d40 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.bulkupdate.md +++ b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.bulkupdate.md @@ -9,7 +9,7 @@ Update multiple documents at once Signature: ```typescript -bulkUpdate(objects?: SavedObjectsBulkUpdateObject[]): Promise>; +bulkUpdate(objects?: SavedObjectsBulkUpdateObject[]): Promise>; ``` ## Parameters @@ -20,7 +20,7 @@ bulkUpdate(objects?: SavedObjectsBulkUpdateObje Returns: -`Promise>` +`Promise>` The result of the update operation containing both failed and updated saved objects. diff --git a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.create.md b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.create.md index 5a7666084ea0f..ea3fbe31ca8a5 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.create.md +++ b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.create.md @@ -9,5 +9,5 @@ Persists an object Signature: ```typescript -create: (type: string, attributes: T, options?: SavedObjectsCreateOptions) => Promise>; +create: (type: string, attributes: T, options?: SavedObjectsCreateOptions) => Promise>; ``` diff --git a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.find.md b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.find.md index d3494045952ad..3d8005c9390b7 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.find.md +++ b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.find.md @@ -9,5 +9,5 @@ Search for objects Signature: ```typescript -find: (options: Pick) => Promise>; +find: (options: Pick) => Promise>; ``` diff --git a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.get.md b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.get.md index bddbadd3e1361..37a91f7211da5 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.get.md +++ b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.get.md @@ -9,5 +9,5 @@ Fetches a single object Signature: ```typescript -get: (type: string, id: string) => Promise>; +get: (type: string, id: string) => Promise>; ``` diff --git a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.md b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.md index 7aa17eae2da87..5c22a2a0bdd91 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.md +++ b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.md @@ -20,12 +20,12 @@ The constructor for this class is marked as internal. Third-party code should no | Property | Modifiers | Type | Description | | --- | --- | --- | --- | -| [bulkCreate](./kibana-plugin-public.savedobjectsclient.bulkcreate.md) | | (objects?: SavedObjectsBulkCreateObject<SavedObjectAttributes>[], options?: SavedObjectsBulkCreateOptions) => Promise<SavedObjectsBatchResponse<SavedObjectAttributes>> | Creates multiple documents at once | -| [bulkGet](./kibana-plugin-public.savedobjectsclient.bulkget.md) | | (objects?: {
id: string;
type: string;
}[]) => Promise<SavedObjectsBatchResponse<SavedObjectAttributes>> | Returns an array of objects by id | -| [create](./kibana-plugin-public.savedobjectsclient.create.md) | | <T extends SavedObjectAttributes>(type: string, attributes: T, options?: SavedObjectsCreateOptions) => Promise<SimpleSavedObject<T>> | Persists an object | +| [bulkCreate](./kibana-plugin-public.savedobjectsclient.bulkcreate.md) | | (objects?: SavedObjectsBulkCreateObject<unknown>[], options?: SavedObjectsBulkCreateOptions) => Promise<SavedObjectsBatchResponse<unknown>> | Creates multiple documents at once | +| [bulkGet](./kibana-plugin-public.savedobjectsclient.bulkget.md) | | (objects?: {
id: string;
type: string;
}[]) => Promise<SavedObjectsBatchResponse<unknown>> | Returns an array of objects by id | +| [create](./kibana-plugin-public.savedobjectsclient.create.md) | | <T = unknown>(type: string, attributes: T, options?: SavedObjectsCreateOptions) => Promise<SimpleSavedObject<T>> | Persists an object | | [delete](./kibana-plugin-public.savedobjectsclient.delete.md) | | (type: string, id: string) => Promise<{}> | Deletes an object | -| [find](./kibana-plugin-public.savedobjectsclient.find.md) | | <T extends SavedObjectAttributes>(options: Pick<SavedObjectFindOptionsServer, "search" | "filter" | "type" | "page" | "perPage" | "sortField" | "fields" | "searchFields" | "hasReference" | "defaultSearchOperator">) => Promise<SavedObjectsFindResponsePublic<T>> | Search for objects | -| [get](./kibana-plugin-public.savedobjectsclient.get.md) | | <T extends SavedObjectAttributes>(type: string, id: string) => Promise<SimpleSavedObject<T>> | Fetches a single object | +| [find](./kibana-plugin-public.savedobjectsclient.find.md) | | <T = unknown>(options: Pick<SavedObjectFindOptionsServer, "search" | "filter" | "type" | "page" | "perPage" | "sortField" | "fields" | "searchFields" | "hasReference" | "defaultSearchOperator">) => Promise<SavedObjectsFindResponsePublic<T>> | Search for objects | +| [get](./kibana-plugin-public.savedobjectsclient.get.md) | | <T = unknown>(type: string, id: string) => Promise<SimpleSavedObject<T>> | Fetches a single object | ## Methods diff --git a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.update.md b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.update.md index 9f7e46943bbd5..d1049a75edf1f 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobjectsclient.update.md +++ b/docs/development/core/public/kibana-plugin-public.savedobjectsclient.update.md @@ -9,7 +9,7 @@ Updates an object Signature: ```typescript -update(type: string, id: string, attributes: T, { version, migrationVersion, references }?: SavedObjectsUpdateOptions): Promise>; +update(type: string, id: string, attributes: T, { version, migrationVersion, references }?: SavedObjectsUpdateOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/public/kibana-plugin-public.savedobjectsfindresponsepublic.md b/docs/development/core/public/kibana-plugin-public.savedobjectsfindresponsepublic.md index f60e7305fba34..31ab73464dfd9 100644 --- a/docs/development/core/public/kibana-plugin-public.savedobjectsfindresponsepublic.md +++ b/docs/development/core/public/kibana-plugin-public.savedobjectsfindresponsepublic.md @@ -11,7 +11,7 @@ Return type of the Saved Objects `find()` method. Signature: ```typescript -export interface SavedObjectsFindResponsePublic extends SavedObjectsBatchResponse +export interface SavedObjectsFindResponsePublic extends SavedObjectsBatchResponse ``` ## Properties diff --git a/docs/development/core/public/kibana-plugin-public.simplesavedobject.md b/docs/development/core/public/kibana-plugin-public.simplesavedobject.md index 1f6de163ec17d..4906d5967f7df 100644 --- a/docs/development/core/public/kibana-plugin-public.simplesavedobject.md +++ b/docs/development/core/public/kibana-plugin-public.simplesavedobject.md @@ -11,7 +11,7 @@ It provides basic functionality for creating/saving/deleting saved objects, but Signature: ```typescript -export declare class SimpleSavedObject +export declare class SimpleSavedObject ``` ## Constructors diff --git a/docs/development/core/server/kibana-plugin-server.savedobject.md b/docs/development/core/server/kibana-plugin-server.savedobject.md index b3184fd38ad93..5ab08f4eadf2e 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobject.md +++ b/docs/development/core/server/kibana-plugin-server.savedobject.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface SavedObject +export interface SavedObject ``` ## Properties diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsbulkcreateobject.md b/docs/development/core/server/kibana-plugin-server.savedobjectsbulkcreateobject.md index 87386b986009d..7b765055de6c1 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsbulkcreateobject.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsbulkcreateobject.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface SavedObjectsBulkCreateObject +export interface SavedObjectsBulkCreateObject ``` ## Properties diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsbulkresponse.md b/docs/development/core/server/kibana-plugin-server.savedobjectsbulkresponse.md index 20a1194c87eda..2ced4f4c8e1a0 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsbulkresponse.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsbulkresponse.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface SavedObjectsBulkResponse +export interface SavedObjectsBulkResponse ``` ## Properties diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsbulkupdateobject.md b/docs/development/core/server/kibana-plugin-server.savedobjectsbulkupdateobject.md index 8e4e3d761148e..67013290a629d 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsbulkupdateobject.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsbulkupdateobject.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface SavedObjectsBulkUpdateObject extends Pick +export interface SavedObjectsBulkUpdateObject extends Pick ``` ## Properties diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsbulkupdateresponse.md b/docs/development/core/server/kibana-plugin-server.savedobjectsbulkupdateresponse.md index 065b9df0823cd..3468991611608 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsbulkupdateresponse.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsbulkupdateresponse.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface SavedObjectsBulkUpdateResponse +export interface SavedObjectsBulkUpdateResponse ``` ## Properties diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.bulkcreate.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.bulkcreate.md index 40f947188de54..47da795631a3a 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.bulkcreate.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.bulkcreate.md @@ -9,7 +9,7 @@ Persists multiple documents batched together as a single request Signature: ```typescript -bulkCreate(objects: Array>, options?: SavedObjectsCreateOptions): Promise>; +bulkCreate(objects: Array>, options?: SavedObjectsCreateOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.bulkget.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.bulkget.md index c86c30d14db3b..71006e2afa3ee 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.bulkget.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.bulkget.md @@ -9,7 +9,7 @@ Returns an array of objects by id Signature: ```typescript -bulkGet(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise>; +bulkGet(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.bulkupdate.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.bulkupdate.md index 33958837ebca3..cceeb9c1ca320 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.bulkupdate.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.bulkupdate.md @@ -9,7 +9,7 @@ Bulk Updates multiple SavedObject at once Signature: ```typescript -bulkUpdate(objects: Array>, options?: SavedObjectsBulkUpdateOptions): Promise>; +bulkUpdate(objects: Array>, options?: SavedObjectsBulkUpdateOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.create.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.create.md index ddb78a57e71bc..7f6fc117937cb 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.create.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.create.md @@ -9,7 +9,7 @@ Persists a SavedObject Signature: ```typescript -create(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise>; +create(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.find.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.find.md index f72691d3ce0c8..c8804e2a97851 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.find.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.find.md @@ -9,7 +9,7 @@ Find all SavedObjects matching the search query Signature: ```typescript -find(options: SavedObjectsFindOptions): Promise>; +find(options: SavedObjectsFindOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.get.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.get.md index 3906462184d4f..b48cef25ca3d1 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.get.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.get.md @@ -9,7 +9,7 @@ Retrieves a single object Signature: ```typescript -get(type: string, id: string, options?: SavedObjectsBaseOptions): Promise>; +get(type: string, id: string, options?: SavedObjectsBaseOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.update.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.update.md index 2c71e518b7b05..ed6243c409fa4 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsclient.update.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclient.update.md @@ -9,7 +9,7 @@ Updates an SavedObject Signature: ```typescript -update(type: string, id: string, attributes: Partial, options?: SavedObjectsUpdateOptions): Promise>; +update(type: string, id: string, attributes: Partial, options?: SavedObjectsUpdateOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsfindresponse.md b/docs/development/core/server/kibana-plugin-server.savedobjectsfindresponse.md index efdc07cea88fd..a79a23db967cc 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsfindresponse.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsfindresponse.md @@ -11,7 +11,7 @@ Return type of the Saved Objects `find()` method. Signature: ```typescript -export interface SavedObjectsFindResponse +export interface SavedObjectsFindResponse ``` ## Properties diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.bulkcreate.md b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.bulkcreate.md index dfe9e51e62483..f0d8d9edfbe79 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.bulkcreate.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.bulkcreate.md @@ -9,7 +9,7 @@ Creates multiple documents at once Signature: ```typescript -bulkCreate(objects: Array>, options?: SavedObjectsCreateOptions): Promise>; +bulkCreate(objects: Array>, options?: SavedObjectsCreateOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.bulkget.md b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.bulkget.md index 34b113bce5410..e27c5fc3bec9a 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.bulkget.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.bulkget.md @@ -9,7 +9,7 @@ Returns an array of objects by id Signature: ```typescript -bulkGet(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise>; +bulkGet(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.bulkupdate.md b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.bulkupdate.md index 23c7a92624957..5ad09d59f4061 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.bulkupdate.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.bulkupdate.md @@ -9,7 +9,7 @@ Updates multiple objects in bulk Signature: ```typescript -bulkUpdate(objects: Array>, options?: SavedObjectsBulkUpdateOptions): Promise>; +bulkUpdate(objects: Array>, options?: SavedObjectsBulkUpdateOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.create.md b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.create.md index 29e3c3ab24654..fd6495bd2d3c4 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.create.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.create.md @@ -9,7 +9,7 @@ Persists an object Signature: ```typescript -create(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise>; +create(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.find.md b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.find.md index dbf6d59e78d85..ccb9feca1669e 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.find.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.find.md @@ -7,7 +7,7 @@ Signature: ```typescript -find({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, }: SavedObjectsFindOptions): Promise>; +find({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, }: SavedObjectsFindOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.get.md b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.get.md index 930a4647ca175..b3ccbc7277b4e 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.get.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.get.md @@ -9,7 +9,7 @@ Gets a single object Signature: ```typescript -get(type: string, id: string, options?: SavedObjectsBaseOptions): Promise>; +get(type: string, id: string, options?: SavedObjectsBaseOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.update.md b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.update.md index 5e9f69ecc567b..bb215cdb97af5 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.update.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsrepository.update.md @@ -9,7 +9,7 @@ Updates an object Signature: ```typescript -update(type: string, id: string, attributes: Partial, options?: SavedObjectsUpdateOptions): Promise>; +update(type: string, id: string, attributes: Partial, options?: SavedObjectsUpdateOptions): Promise>; ``` ## Parameters diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsupdateresponse.md b/docs/development/core/server/kibana-plugin-server.savedobjectsupdateresponse.md index 64c9037735358..130b0b4faaa07 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsupdateresponse.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsupdateresponse.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface SavedObjectsUpdateResponse extends Omit, 'attributes' | 'references'> +export interface SavedObjectsUpdateResponse extends Omit, 'attributes' | 'references'> ``` ## Properties diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index ca2f6789bebee..ba1988b857385 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -932,7 +932,7 @@ export type RecursiveReadonly = T extends (...args: any[]) => any ? T : T ext }> : T; // @public (undocumented) -export interface SavedObject { +export interface SavedObject { attributes: T; // (undocumented) error?: { @@ -975,13 +975,13 @@ export interface SavedObjectsBaseOptions { } // @public (undocumented) -export interface SavedObjectsBatchResponse { +export interface SavedObjectsBatchResponse { // (undocumented) savedObjects: Array>; } // @public (undocumented) -export interface SavedObjectsBulkCreateObject extends SavedObjectsCreateOptions { +export interface SavedObjectsBulkCreateObject extends SavedObjectsCreateOptions { // (undocumented) attributes: T; // (undocumented) @@ -994,7 +994,7 @@ export interface SavedObjectsBulkCreateOptions { } // @public (undocumented) -export interface SavedObjectsBulkUpdateObject { +export interface SavedObjectsBulkUpdateObject { // (undocumented) attributes: T; // (undocumented) @@ -1017,17 +1017,17 @@ export interface SavedObjectsBulkUpdateOptions { export class SavedObjectsClient { // @internal constructor(http: HttpSetup); - bulkCreate: (objects?: SavedObjectsBulkCreateObject[], options?: SavedObjectsBulkCreateOptions) => Promise>; + bulkCreate: (objects?: SavedObjectsBulkCreateObject[], options?: SavedObjectsBulkCreateOptions) => Promise>; bulkGet: (objects?: { id: string; type: string; - }[]) => Promise>; - bulkUpdate(objects?: SavedObjectsBulkUpdateObject[]): Promise>; - create: (type: string, attributes: T, options?: SavedObjectsCreateOptions) => Promise>; + }[]) => Promise>; + bulkUpdate(objects?: SavedObjectsBulkUpdateObject[]): Promise>; + create: (type: string, attributes: T, options?: SavedObjectsCreateOptions) => Promise>; delete: (type: string, id: string) => Promise<{}>; - find: (options: Pick) => Promise>; - get: (type: string, id: string) => Promise>; - update(type: string, id: string, attributes: T, { version, migrationVersion, references }?: SavedObjectsUpdateOptions): Promise>; + find: (options: Pick) => Promise>; + get: (type: string, id: string) => Promise>; + update(type: string, id: string, attributes: T, { version, migrationVersion, references }?: SavedObjectsUpdateOptions): Promise>; } // @public @@ -1069,7 +1069,7 @@ export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions { } // @public -export interface SavedObjectsFindResponsePublic extends SavedObjectsBatchResponse { +export interface SavedObjectsFindResponsePublic extends SavedObjectsBatchResponse { // (undocumented) page: number; // (undocumented) @@ -1176,7 +1176,7 @@ export interface SavedObjectsUpdateOptions { } // @public -export class SimpleSavedObject { +export class SimpleSavedObject { constructor(client: SavedObjectsClientContract, { id, type, version, attributes, error, references, migrationVersion }: SavedObject); // (undocumented) attributes: T; diff --git a/src/core/public/saved_objects/saved_objects_client.ts b/src/core/public/saved_objects/saved_objects_client.ts index ccb23793a8534..afc77806afb91 100644 --- a/src/core/public/saved_objects/saved_objects_client.ts +++ b/src/core/public/saved_objects/saved_objects_client.ts @@ -22,7 +22,6 @@ import { resolve as resolveUrl } from 'url'; import { SavedObject, - SavedObjectAttributes, SavedObjectReference, SavedObjectsClientContract as SavedObjectsApi, SavedObjectsFindOptions as SavedObjectFindOptionsServer, @@ -61,9 +60,7 @@ export interface SavedObjectsCreateOptions { * * @public */ -export interface SavedObjectsBulkCreateObject< - T extends SavedObjectAttributes = SavedObjectAttributes -> extends SavedObjectsCreateOptions { +export interface SavedObjectsBulkCreateObject extends SavedObjectsCreateOptions { type: string; attributes: T; } @@ -75,9 +72,7 @@ export interface SavedObjectsBulkCreateOptions { } /** @public */ -export interface SavedObjectsBulkUpdateObject< - T extends SavedObjectAttributes = SavedObjectAttributes -> { +export interface SavedObjectsBulkUpdateObject { type: string; id: string; attributes: T; @@ -99,9 +94,7 @@ export interface SavedObjectsUpdateOptions { } /** @public */ -export interface SavedObjectsBatchResponse< - T extends SavedObjectAttributes = SavedObjectAttributes -> { +export interface SavedObjectsBatchResponse { savedObjects: Array>; } @@ -113,9 +106,7 @@ export interface SavedObjectsBatchResponse< * * @public */ -export interface SavedObjectsFindResponsePublic< - T extends SavedObjectAttributes = SavedObjectAttributes -> extends SavedObjectsBatchResponse { +export interface SavedObjectsFindResponsePublic extends SavedObjectsBatchResponse { total: number; perPage: number; page: number; @@ -124,7 +115,7 @@ export interface SavedObjectsFindResponsePublic< interface BatchQueueEntry { type: string; id: string; - resolve: (value: SimpleSavedObject | SavedObject) => void; + resolve: (value: SimpleSavedObject | SavedObject) => void; reject: (reason?: any) => void; } @@ -207,7 +198,7 @@ export class SavedObjectsClient { * @param options * @returns */ - public create = ( + public create = ( type: string, attributes: T, options: SavedObjectsCreateOptions = {} @@ -300,7 +291,7 @@ export class SavedObjectsClient { * @property {object} [options.hasReference] - { type, id } * @returns A find result with objects matching the specified search. */ - public find = ( + public find = ( options: SavedObjectsFindOptions ): Promise> => { const path = this.getPath(['_find']); @@ -348,10 +339,7 @@ export class SavedObjectsClient { * @param {string} id * @returns The saved object for the given type and id. */ - public get = ( - type: string, - id: string - ): Promise> => { + public get = (type: string, id: string): Promise> => { if (!type || !id) { return Promise.reject(new Error('requires type and id')); } @@ -402,7 +390,7 @@ export class SavedObjectsClient { * @prop {object} options.migrationVersion - The optional migrationVersion of this document * @returns */ - public update( + public update( type: string, id: string, attributes: T, @@ -434,7 +422,7 @@ export class SavedObjectsClient { * @param {array} objects - [{ type, id, attributes, options: { version, references } }] * @returns The result of the update operation containing both failed and updated saved objects. */ - public bulkUpdate(objects: SavedObjectsBulkUpdateObject[] = []) { + public bulkUpdate(objects: SavedObjectsBulkUpdateObject[] = []) { const path = this.getPath(['_bulk_update']); return this.savedObjectsFetch(path, { @@ -449,9 +437,7 @@ export class SavedObjectsClient { }); } - private createSavedObject( - options: SavedObject - ): SimpleSavedObject { + private createSavedObject(options: SavedObject): SimpleSavedObject { return new SimpleSavedObject(this, options); } diff --git a/src/core/public/saved_objects/simple_saved_object.ts b/src/core/public/saved_objects/simple_saved_object.ts index 8e464680bcf17..d3ba506b865a4 100644 --- a/src/core/public/saved_objects/simple_saved_object.ts +++ b/src/core/public/saved_objects/simple_saved_object.ts @@ -18,7 +18,7 @@ */ import { get, has, set } from 'lodash'; -import { SavedObject as SavedObjectType, SavedObjectAttributes } from '../../server'; +import { SavedObject as SavedObjectType } from '../../server'; import { SavedObjectsClientContract } from './saved_objects_client'; /** @@ -30,7 +30,7 @@ import { SavedObjectsClientContract } from './saved_objects_client'; * * @public */ -export class SimpleSavedObject { +export class SimpleSavedObject { public attributes: T; // We want to use the same interface this class had in JS public _version?: SavedObjectType['version']; @@ -46,7 +46,7 @@ export class SimpleSavedObject { ) { this.id = id; this.type = type; - this.attributes = attributes || {}; + this.attributes = attributes || ({} as T); this.references = references || []; this._version = version; this.migrationVersion = migrationVersion; diff --git a/src/core/server/saved_objects/import/collect_saved_objects.ts b/src/core/server/saved_objects/import/collect_saved_objects.ts index 65ffd4d9a1d57..1a8ede41d0b2c 100644 --- a/src/core/server/saved_objects/import/collect_saved_objects.ts +++ b/src/core/server/saved_objects/import/collect_saved_objects.ts @@ -42,10 +42,10 @@ export async function collectSavedObjects({ supportedTypes, }: CollectSavedObjectsOptions) { const errors: SavedObjectsImportError[] = []; - const collectedObjects: SavedObject[] = await createPromiseFromStreams([ + const collectedObjects: Array> = await createPromiseFromStreams([ readStream, createLimitStream(objectLimit), - createFilterStream(obj => { + createFilterStream>(obj => { if (supportedTypes.includes(obj.type)) { return true; } diff --git a/src/core/server/saved_objects/import/extract_errors.ts b/src/core/server/saved_objects/import/extract_errors.ts index 725e935f6e21d..5728ce8b7b59f 100644 --- a/src/core/server/saved_objects/import/extract_errors.ts +++ b/src/core/server/saved_objects/import/extract_errors.ts @@ -20,11 +20,12 @@ import { SavedObject } from '../types'; import { SavedObjectsImportError } from './types'; export function extractErrors( - savedObjectResults: SavedObject[], - savedObjectsToImport: SavedObject[] + // TODO: define saved object type + savedObjectResults: Array>, + savedObjectsToImport: Array> ) { const errors: SavedObjectsImportError[] = []; - const originalSavedObjectsMap = new Map(); + const originalSavedObjectsMap = new Map>(); for (const savedObject of savedObjectsToImport) { originalSavedObjectsMap.set(`${savedObject.type}:${savedObject.id}`, savedObject); } diff --git a/src/core/server/saved_objects/import/validate_references.ts b/src/core/server/saved_objects/import/validate_references.ts index 4d9ee59f9df15..f0c033c1d00b4 100644 --- a/src/core/server/saved_objects/import/validate_references.ts +++ b/src/core/server/saved_objects/import/validate_references.ts @@ -77,7 +77,7 @@ export async function getNonExistingReferenceAsKeys( } export async function validateReferences( - savedObjects: SavedObject[], + savedObjects: Array>, savedObjectsClient: SavedObjectsClientContract, namespace?: string ) { diff --git a/src/core/server/saved_objects/management/management.ts b/src/core/server/saved_objects/management/management.ts index 7b5274da91fc8..b7dce2c087c5f 100644 --- a/src/core/server/saved_objects/management/management.ts +++ b/src/core/server/saved_objects/management/management.ts @@ -23,9 +23,9 @@ interface SavedObjectsManagementTypeDefinition { isImportableAndExportable?: boolean; defaultSearchField?: string; icon?: string; - getTitle?: (savedObject: SavedObject) => string; - getEditUrl?: (savedObject: SavedObject) => string; - getInAppUrl?: (savedObject: SavedObject) => { path: string; uiCapabilitiesPath: string }; + getTitle?: (savedObject: SavedObject) => string; + getEditUrl?: (savedObject: SavedObject) => string; + getInAppUrl?: (savedObject: SavedObject) => { path: string; uiCapabilitiesPath: string }; } export interface SavedObjectsManagementDefinition { diff --git a/src/core/server/saved_objects/serialization/types.ts b/src/core/server/saved_objects/serialization/types.ts index aaf6f45c244ec..524c2c8ffae7a 100644 --- a/src/core/server/saved_objects/serialization/types.ts +++ b/src/core/server/saved_objects/serialization/types.ts @@ -50,7 +50,7 @@ export interface SavedObjectsRawDocSource { * scenario out of the box. */ interface SavedObjectDoc { - attributes: object; + attributes: unknown; id?: string; // NOTE: SavedObjectDoc is used for uncreated objects where `id` is optional type: string; namespace?: string; diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index b485b8dfe398c..72a7867854b60 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -48,7 +48,6 @@ import { } from '../saved_objects_client'; import { SavedObject, - SavedObjectAttributes, SavedObjectsBaseOptions, SavedObjectsFindOptions, SavedObjectsMigrationVersion, @@ -213,7 +212,7 @@ export class SavedObjectsRepository { * @property {array} [options.references=[]] - [{ name, type, id }] * @returns {promise} - { id, type, version, attributes } */ - public async create( + public async create( type: string, attributes: T, options: SavedObjectsCreateOptions = {} @@ -254,7 +253,7 @@ export class SavedObjectsRepository { body: raw._source, }); - return this._rawToSavedObject({ + return this._rawToSavedObject({ ...raw, ...response, }); @@ -277,7 +276,7 @@ export class SavedObjectsRepository { * @property {string} [options.namespace] * @returns {promise} - {saved_objects: [[{ id, type, version, references, attributes, error: { message } }]} */ - async bulkCreate( + async bulkCreate( objects: Array>, options: SavedObjectsCreateOptions = {} ): Promise> { @@ -464,7 +463,7 @@ export class SavedObjectsRepository { * @property {object} [options.hasReference] - { type, id } * @returns {promise} - { saved_objects: [{ id, type, version, attributes }], total, per_page, page } */ - async find({ + async find({ search, defaultSearchOperator = 'OR', searchFields, @@ -577,7 +576,7 @@ export class SavedObjectsRepository { * { id: 'foo', type: 'index-pattern' } * ]) */ - async bulkGet( + async bulkGet( objects: SavedObjectsBulkGetObject[] = [], options: SavedObjectsBaseOptions = {} ): Promise> { @@ -648,7 +647,7 @@ export class SavedObjectsRepository { * @property {string} [options.namespace] * @returns {promise} - { id, type, version, attributes } */ - async get( + async get( type: string, id: string, options: SavedObjectsBaseOptions = {} @@ -696,7 +695,7 @@ export class SavedObjectsRepository { * @property {array} [options.references] - [{ name, type, id }] * @returns {promise} */ - async update( + async update( type: string, id: string, attributes: Partial, @@ -753,7 +752,7 @@ export class SavedObjectsRepository { * @property {string} [options.namespace] * @returns {promise} - {saved_objects: [[{ id, type, version, references, attributes, error: { message } }]} */ - async bulkUpdate( + async bulkUpdate( objects: Array>, options: SavedObjectsBulkUpdateOptions = {} ): Promise> { @@ -972,7 +971,7 @@ export class SavedObjectsRepository { // includes the namespace, and we use this for migrating documents. However, we don't // want the namespace to be returned from the repository, as the repository scopes each // method transparently to the specified namespace. - private _rawToSavedObject(raw: SavedObjectsRawDoc): SavedObject { + private _rawToSavedObject(raw: SavedObjectsRawDoc): SavedObject { const savedObject = this._serializer.rawToSavedObject(raw); return omit(savedObject, 'namespace'); } diff --git a/src/core/server/saved_objects/service/saved_objects_client.ts b/src/core/server/saved_objects/service/saved_objects_client.ts index b0b2633646e10..70d69374ba8fe 100644 --- a/src/core/server/saved_objects/service/saved_objects_client.ts +++ b/src/core/server/saved_objects/service/saved_objects_client.ts @@ -20,7 +20,6 @@ import { ISavedObjectsRepository } from './lib'; import { SavedObject, - SavedObjectAttributes, SavedObjectReference, SavedObjectsMigrationVersion, SavedObjectsBaseOptions, @@ -49,7 +48,7 @@ export interface SavedObjectsCreateOptions extends SavedObjectsBaseOptions { * * @public */ -export interface SavedObjectsBulkCreateObject { +export interface SavedObjectsBulkCreateObject { id?: string; type: string; attributes: T; @@ -62,7 +61,7 @@ export interface SavedObjectsBulkCreateObject +export interface SavedObjectsBulkUpdateObject extends Pick { /** The ID of this Saved Object, guaranteed to be unique for all objects of the same `type` */ id: string; @@ -76,7 +75,7 @@ export interface SavedObjectsBulkUpdateObject { +export interface SavedObjectsBulkResponse { saved_objects: Array>; } @@ -88,7 +87,7 @@ export interface SavedObjectsBulkResponse * * @public */ -export interface SavedObjectsFindResponse { +export interface SavedObjectsFindResponse { saved_objects: Array>; total: number; per_page: number; @@ -141,7 +140,7 @@ export interface SavedObjectsBulkGetObject { * * @public */ -export interface SavedObjectsBulkResponse { +export interface SavedObjectsBulkResponse { saved_objects: Array>; } @@ -149,7 +148,7 @@ export interface SavedObjectsBulkResponse * * @public */ -export interface SavedObjectsBulkUpdateResponse { +export interface SavedObjectsBulkUpdateResponse { saved_objects: Array>; } @@ -157,7 +156,7 @@ export interface SavedObjectsBulkUpdateResponse +export interface SavedObjectsUpdateResponse extends Omit, 'attributes' | 'references'> { attributes: Partial; references: SavedObjectReference[] | undefined; @@ -185,11 +184,7 @@ export class SavedObjectsClient { * @param attributes * @param options */ - async create( - type: string, - attributes: T, - options?: SavedObjectsCreateOptions - ) { + async create(type: string, attributes: T, options?: SavedObjectsCreateOptions) { return await this._repository.create(type, attributes, options); } @@ -199,7 +194,7 @@ export class SavedObjectsClient { * @param objects * @param options */ - async bulkCreate( + async bulkCreate( objects: Array>, options?: SavedObjectsCreateOptions ) { @@ -222,9 +217,7 @@ export class SavedObjectsClient { * * @param options */ - async find( - options: SavedObjectsFindOptions - ): Promise> { + async find(options: SavedObjectsFindOptions): Promise> { return await this._repository.find(options); } @@ -239,7 +232,7 @@ export class SavedObjectsClient { * { id: 'foo', type: 'index-pattern' } * ]) */ - async bulkGet( + async bulkGet( objects: SavedObjectsBulkGetObject[] = [], options: SavedObjectsBaseOptions = {} ): Promise> { @@ -253,7 +246,7 @@ export class SavedObjectsClient { * @param id - The ID of the SavedObject to retrieve * @param options */ - async get( + async get( type: string, id: string, options: SavedObjectsBaseOptions = {} @@ -268,7 +261,7 @@ export class SavedObjectsClient { * @param id * @param options */ - async update( + async update( type: string, id: string, attributes: Partial, @@ -282,7 +275,7 @@ export class SavedObjectsClient { * * @param objects */ - async bulkUpdate( + async bulkUpdate( objects: Array>, options?: SavedObjectsBulkUpdateOptions ): Promise> { diff --git a/src/core/server/saved_objects/types.ts b/src/core/server/saved_objects/types.ts index a4fde1765b7d3..9c204784b0aeb 100644 --- a/src/core/server/saved_objects/types.ts +++ b/src/core/server/saved_objects/types.ts @@ -33,7 +33,6 @@ export { SavedObjectsImportRetry, } from './import/types'; -import { SavedObjectAttributes } from '../../types'; import { LegacyConfig } from '../legacy'; export { SavedObjectAttributes, @@ -64,7 +63,7 @@ export interface SavedObjectsMigrationVersion { * * @public */ -export interface SavedObject { +export interface SavedObject { /** The ID of this Saved Object, guaranteed to be unique for all objects of the same `type` */ id: string; /** The type of Saved Object. Each plugin can define it's own custom Saved Object types. */ diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 053a60028fc5f..f717f30fdb0cf 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -1462,7 +1462,7 @@ export interface RouteValidatorOptions { } // @public (undocumented) -export interface SavedObject { +export interface SavedObject { attributes: T; // (undocumented) error?: { @@ -1524,7 +1524,7 @@ export interface SavedObjectsBaseOptions { } // @public (undocumented) -export interface SavedObjectsBulkCreateObject { +export interface SavedObjectsBulkCreateObject { // (undocumented) attributes: T; // (undocumented) @@ -1546,19 +1546,19 @@ export interface SavedObjectsBulkGetObject { } // @public (undocumented) -export interface SavedObjectsBulkResponse { +export interface SavedObjectsBulkResponse { // (undocumented) saved_objects: Array>; } // @public (undocumented) -export interface SavedObjectsBulkResponse { +export interface SavedObjectsBulkResponse { // (undocumented) saved_objects: Array>; } // @public (undocumented) -export interface SavedObjectsBulkUpdateObject extends Pick { +export interface SavedObjectsBulkUpdateObject extends Pick { attributes: Partial; id: string; type: string; @@ -1570,7 +1570,7 @@ export interface SavedObjectsBulkUpdateOptions extends SavedObjectsBaseOptions { } // @public (undocumented) -export interface SavedObjectsBulkUpdateResponse { +export interface SavedObjectsBulkUpdateResponse { // (undocumented) saved_objects: Array>; } @@ -1579,18 +1579,18 @@ export interface SavedObjectsBulkUpdateResponse(objects: Array>, options?: SavedObjectsCreateOptions): Promise>; - bulkGet(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise>; - bulkUpdate(objects: Array>, options?: SavedObjectsBulkUpdateOptions): Promise>; - create(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise>; + bulkCreate(objects: Array>, options?: SavedObjectsCreateOptions): Promise>; + bulkGet(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise>; + bulkUpdate(objects: Array>, options?: SavedObjectsBulkUpdateOptions): Promise>; + create(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise>; delete(type: string, id: string, options?: SavedObjectsDeleteOptions): Promise<{}>; // (undocumented) static errors: typeof SavedObjectsErrorHelpers; // (undocumented) errors: typeof SavedObjectsErrorHelpers; - find(options: SavedObjectsFindOptions): Promise>; - get(type: string, id: string, options?: SavedObjectsBaseOptions): Promise>; - update(type: string, id: string, attributes: Partial, options?: SavedObjectsUpdateOptions): Promise>; + find(options: SavedObjectsFindOptions): Promise>; + get(type: string, id: string, options?: SavedObjectsBaseOptions): Promise>; + update(type: string, id: string, attributes: Partial, options?: SavedObjectsUpdateOptions): Promise>; } // @public @@ -1772,7 +1772,7 @@ export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions { } // @public -export interface SavedObjectsFindResponse { +export interface SavedObjectsFindResponse { // (undocumented) page: number; // (undocumented) @@ -1951,10 +1951,10 @@ export interface SavedObjectsRawDoc { // @public (undocumented) export class SavedObjectsRepository { - bulkCreate(objects: Array>, options?: SavedObjectsCreateOptions): Promise>; - bulkGet(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise>; - bulkUpdate(objects: Array>, options?: SavedObjectsBulkUpdateOptions): Promise>; - create(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise>; + bulkCreate(objects: Array>, options?: SavedObjectsCreateOptions): Promise>; + bulkGet(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise>; + bulkUpdate(objects: Array>, options?: SavedObjectsBulkUpdateOptions): Promise>; + create(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise>; // Warning: (ae-forgotten-export) The symbol "KibanaMigrator" needs to be exported by the entry point index.d.ts // // @internal @@ -1962,8 +1962,8 @@ export class SavedObjectsRepository { delete(type: string, id: string, options?: SavedObjectsDeleteOptions): Promise<{}>; deleteByNamespace(namespace: string, options?: SavedObjectsDeleteByNamespaceOptions): Promise; // (undocumented) - find({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, }: SavedObjectsFindOptions): Promise>; - get(type: string, id: string, options?: SavedObjectsBaseOptions): Promise>; + find({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, }: SavedObjectsFindOptions): Promise>; + get(type: string, id: string, options?: SavedObjectsBaseOptions): Promise>; incrementCounter(type: string, id: string, counterFieldName: string, options?: SavedObjectsIncrementCounterOptions): Promise<{ id: string; type: string; @@ -1972,7 +1972,7 @@ export class SavedObjectsRepository { version: string; attributes: any; }>; - update(type: string, id: string, attributes: Partial, options?: SavedObjectsUpdateOptions): Promise>; + update(type: string, id: string, attributes: Partial, options?: SavedObjectsUpdateOptions): Promise>; } // @public @@ -2062,7 +2062,7 @@ export interface SavedObjectsUpdateOptions extends SavedObjectsBaseOptions { } // @public (undocumented) -export interface SavedObjectsUpdateResponse extends Omit, 'attributes' | 'references'> { +export interface SavedObjectsUpdateResponse extends Omit, 'attributes' | 'references'> { // (undocumented) attributes: Partial; // (undocumented) diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.ts b/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.ts index 0544a1806e09a..55e32b1e3bb37 100644 --- a/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.ts +++ b/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.ts @@ -45,7 +45,10 @@ export async function createOrUpgradeSavedConfig( }); // default to the attributes of the upgradeableConfig if available - const attributes = defaults({ buildNum }, upgradeableConfig ? upgradeableConfig.attributes : {}); + const attributes = defaults( + { buildNum }, + upgradeableConfig ? (upgradeableConfig.attributes as any) : {} + ); try { // create the new SavedConfig diff --git a/src/core/server/ui_settings/ui_settings_client.ts b/src/core/server/ui_settings/ui_settings_client.ts index 3c9c232bff280..a7e55d2b2da65 100644 --- a/src/core/server/ui_settings/ui_settings_client.ts +++ b/src/core/server/ui_settings/ui_settings_client.ts @@ -185,7 +185,7 @@ export class UiSettingsClient implements IUiSettingsClient { autoCreateOrUpgradeIfMissing = true, }: ReadOptions = {}): Promise> { try { - const resp = await this.savedObjectsClient.get(this.type, this.id); + const resp = await this.savedObjectsClient.get>(this.type, this.id); return resp.attributes; } catch (error) { if (SavedObjectsErrorHelpers.isNotFoundError(error) && autoCreateOrUpgradeIfMissing) { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.test.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.test.tsx index 96b8cc383888e..b6fd5ee60b8e2 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.test.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.test.tsx @@ -31,14 +31,14 @@ const indexPattern1 = { attributes: { title: 'test1 title', }, -} as SavedObject; +} as SavedObject; const indexPattern2 = { id: 'test2', attributes: { title: 'test2 title', }, -} as SavedObject; +} as SavedObject; const defaultProps = { indexPatternList: [indexPattern1, indexPattern2], diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.tsx index a4e8ee2ca3d8a..cca523ee2c1bd 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.tsx @@ -18,6 +18,7 @@ */ import React, { useState } from 'react'; import { SavedObject } from 'kibana/server'; +import { IndexPatternAttributes } from 'src/plugins/data/public'; import { I18nProvider } from '@kbn/i18n/react'; import { IndexPatternRef } from './types'; @@ -26,11 +27,11 @@ export interface DiscoverIndexPatternProps { /** * list of available index patterns, if length > 1, component offers a "change" link */ - indexPatternList: SavedObject[]; + indexPatternList: Array>; /** * currently selected index pattern, due to angular issues it's undefined at first rendering */ - selectedIndexPattern: SavedObject; + selectedIndexPattern: SavedObject; /** * triggered when user selects a new index pattern */ diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx index 7cfc7c4dbc81c..bbb6bf26e5b31 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx @@ -24,6 +24,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { indexPatterns, DataPublicPluginStart, + IndexPatternAttributes, } from '../../../../../../../../../../plugins/data/public'; import { SavedObjectsClient, IUiSettingsClient } from '../../../../../../../../../../core/public'; import { MAX_SEARCH_SIZE } from '../../constants'; @@ -96,7 +97,7 @@ export class StepIndexPattern extends Component { - const { savedObjects } = await this.props.savedObjectsClient.find({ + const { savedObjects } = await this.props.savedObjectsClient.find({ type: 'index-pattern', fields: ['title'], perPage: 10000, diff --git a/src/legacy/core_plugins/vis_type_timelion/public/helpers/arg_value_suggestions.ts b/src/legacy/core_plugins/vis_type_timelion/public/helpers/arg_value_suggestions.ts index 95e01f9c8db5b..ea9532964d6fe 100644 --- a/src/legacy/core_plugins/vis_type_timelion/public/helpers/arg_value_suggestions.ts +++ b/src/legacy/core_plugins/vis_type_timelion/public/helpers/arg_value_suggestions.ts @@ -20,7 +20,10 @@ import { get } from 'lodash'; import { getIndexPatterns, getSavedObjectsClient } from './plugin_services'; import { TimelionFunctionArgs } from '../../../../../plugins/timelion/common/types'; -import { indexPatterns as indexPatternsUtils } from '../../../../../plugins/data/public'; +import { + indexPatterns as indexPatternsUtils, + IndexPatternAttributes, +} from '../../../../../plugins/data/public'; export interface Location { min: number; @@ -53,7 +56,7 @@ export function getArgValueSuggestions() { } const indexPatternTitle = get(indexPatternArg, 'value.text'); - const { savedObjects } = await savedObjectsClient.find({ + const { savedObjects } = await savedObjectsClient.find({ type: 'index-pattern', fields: ['title'], search: `"${indexPatternTitle}"`, @@ -84,7 +87,7 @@ export function getArgValueSuggestions() { es: { async index(partial: string) { const search = partial ? `${partial}*` : '*'; - const resp = await savedObjectsClient.find({ + const resp = await savedObjectsClient.find({ type: 'index-pattern', fields: ['title', 'type'], search: `${search}`, diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/get_index_pattern.ts b/src/legacy/core_plugins/visualizations/public/embeddable/get_index_pattern.ts index 25aa77ec73579..cfb2960cfbb7c 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/get_index_pattern.ts +++ b/src/legacy/core_plugins/visualizations/public/embeddable/get_index_pattern.ts @@ -18,7 +18,11 @@ */ import { VisSavedObject } from './visualize_embeddable'; -import { indexPatterns, IIndexPattern } from '../../../../../plugins/data/public'; +import { + indexPatterns, + IIndexPattern, + IndexPatternAttributes, +} from '../../../../../plugins/data/public'; import { getUISettings, getSavedObjects } from '../np_ready/public/services'; export async function getIndexPattern( @@ -32,7 +36,7 @@ export async function getIndexPattern( const defaultIndex = getUISettings().get('defaultIndex'); if (savedVis.vis.params.index_pattern) { - const indexPatternObjects = await savedObjectsClient.find({ + const indexPatternObjects = await savedObjectsClient.find({ type: 'index-pattern', fields: ['title', 'fields'], search: `"${savedVis.vis.params.index_pattern}"`, @@ -42,6 +46,9 @@ export async function getIndexPattern( return indexPattern; } - const savedObject = await savedObjectsClient.get('index-pattern', defaultIndex); + const savedObject = await savedObjectsClient.get( + 'index-pattern', + defaultIndex + ); return indexPatterns.getFromSavedObject(savedObject); } diff --git a/src/plugins/data/common/index_patterns/types.ts b/src/plugins/data/common/index_patterns/types.ts index 98cdd20ea4b84..698edbf9cd6a8 100644 --- a/src/plugins/data/common/index_patterns/types.ts +++ b/src/plugins/data/common/index_patterns/types.ts @@ -34,3 +34,15 @@ export interface IIndexPattern { } >; } + +/** + * Use data plugin interface instead + * @deprecated + */ +export interface IndexPatternAttributes { + type: string; + fields: string; + title: string; + typeMeta: string; + timeFieldName?: string; +} diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index cbd4bfd348797..978f140eb1d26 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -263,6 +263,7 @@ export { IFieldSubType, ES_FIELD_TYPES, KBN_FIELD_TYPES, + IndexPatternAttributes, } from '../common'; /* diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts index 5f95b101302ef..acce5ed57683c 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts +++ b/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts @@ -50,7 +50,7 @@ export class IndexPatternsService { private async refreshSavedObjectsCache() { this.savedObjectsCache = ( - await this.savedObjectsClient.find({ + await this.savedObjectsClient.find>({ type: 'index-pattern', fields: ['title'], perPage: 10000, diff --git a/src/plugins/data/public/index_patterns/lib/get_from_saved_object.ts b/src/plugins/data/public/index_patterns/lib/get_from_saved_object.ts index 60b2023f25609..1630a4547b7a1 100644 --- a/src/plugins/data/public/index_patterns/lib/get_from_saved_object.ts +++ b/src/plugins/data/public/index_patterns/lib/get_from_saved_object.ts @@ -17,17 +17,20 @@ * under the License. */ +import { SavedObject } from 'src/core/public'; import { get } from 'lodash'; -import { IIndexPattern } from '../..'; +import { IIndexPattern, IndexPatternAttributes } from '../..'; -export function getFromSavedObject(savedObject: any): IIndexPattern | undefined { +export function getFromSavedObject( + savedObject: SavedObject +): IIndexPattern | undefined { if (get(savedObject, 'attributes.fields') === undefined) { return; } return { id: savedObject.id, - fields: JSON.parse(savedObject.attributes.fields), + fields: JSON.parse(savedObject.attributes.fields!), title: savedObject.attributes.title, }; } diff --git a/src/plugins/data/public/ui/query_string_input/fetch_index_patterns.ts b/src/plugins/data/public/ui/query_string_input/fetch_index_patterns.ts index 6bef11e4fc46c..1e01d2452ce04 100644 --- a/src/plugins/data/public/ui/query_string_input/fetch_index_patterns.ts +++ b/src/plugins/data/public/ui/query_string_input/fetch_index_patterns.ts @@ -18,7 +18,7 @@ */ import { isEmpty } from 'lodash'; import { IUiSettingsClient, SavedObjectsClientContract } from 'src/core/public'; -import { indexPatterns } from '../..'; +import { indexPatterns, IndexPatternAttributes } from '../..'; export async function fetchIndexPatterns( savedObjectsClient: SavedObjectsClientContract, @@ -30,7 +30,7 @@ export async function fetchIndexPatterns( } const searchString = indexPatternStrings.map(string => `"${string}"`).join(' | '); - const indexPatternsFromSavedObjects = await savedObjectsClient.find({ + const indexPatternsFromSavedObjects = await savedObjectsClient.find({ type: 'index-pattern', fields: ['title', 'fields'], search: searchString, @@ -38,7 +38,7 @@ export async function fetchIndexPatterns( }); const exactMatches = indexPatternsFromSavedObjects.savedObjects.filter(savedObject => { - return indexPatternStrings.includes(savedObject.attributes.title as string); + return indexPatternStrings.includes(savedObject.attributes.title); }); const defaultIndex = uiSettings.get('defaultIndex'); @@ -46,7 +46,10 @@ export async function fetchIndexPatterns( const allMatches = exactMatches.length === indexPatternStrings.length ? exactMatches - : [...exactMatches, await savedObjectsClient.get('index-pattern', defaultIndex)]; + : [ + ...exactMatches, + await savedObjectsClient.get('index-pattern', defaultIndex), + ]; return allMatches.map(indexPatterns.getFromSavedObject); } diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 40d367138b60d..020c3c4c1192d 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -142,6 +142,7 @@ export { IFieldSubType, ES_FIELD_TYPES, KBN_FIELD_TYPES, + IndexPatternAttributes, } from '../common'; /** diff --git a/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts b/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts index 29cf2289fc5b3..bfe99730039d2 100644 --- a/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts +++ b/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts @@ -67,7 +67,7 @@ export interface AppLinkSchema { label: string; } -export interface SampleDatasetSchema { +export interface SampleDatasetSchema { id: string; name: string; description: string; @@ -83,7 +83,7 @@ export interface SampleDatasetSchema { // Kibana saved objects (index patter, visualizations, dashboard, ...) // Should provide a nice demo of Kibana's functionality with the sample data set - savedObjects: SavedObject[]; + savedObjects: Array>; dataIndices: DataIndexSchema[]; status?: string | undefined; statusMsg?: unknown; diff --git a/src/plugins/home/server/services/sample_data/sample_data_registry.ts b/src/plugins/home/server/services/sample_data/sample_data_registry.ts index aac680211e52e..b6d04c5c0b6a3 100644 --- a/src/plugins/home/server/services/sample_data/sample_data_registry.ts +++ b/src/plugins/home/server/services/sample_data/sample_data_registry.ts @@ -137,9 +137,9 @@ export class SampleDataRegistry { throw new Error(`Unable to find sample dataset with id: ${sampleDataId}`); } - const dashboard = sampleDataset.savedObjects.find((savedObject: SavedObject) => { + const dashboard = sampleDataset.savedObjects.find(savedObject => { return savedObject.id === dashboardId && savedObject.type === 'dashboard'; - }); + }) as SavedObject<{ panelsJSON: string }>; if (!dashboard) { throw new Error(`Unable to find dashboard with id: ${dashboardId}`); } diff --git a/src/plugins/saved_objects/public/finder/saved_object_finder.tsx b/src/plugins/saved_objects/public/finder/saved_object_finder.tsx index b503392c9827f..81600e9f68634 100644 --- a/src/plugins/saved_objects/public/finder/saved_object_finder.tsx +++ b/src/plugins/saved_objects/public/finder/saved_object_finder.tsx @@ -43,14 +43,13 @@ import { Direction } from '@elastic/eui/src/services/sort/sort_direction'; import { i18n } from '@kbn/i18n'; import { - SavedObjectAttributes, SimpleSavedObject, CoreStart, IUiSettingsClient, SavedObjectsStart, -} from '../../../../core/public'; +} from 'src/core/public'; -export interface SavedObjectMetaData { +export interface SavedObjectMetaData { type: string; name: string; getIconForSavedObject(savedObject: SimpleSavedObject): IconType; @@ -59,12 +58,17 @@ export interface SavedObjectMetaData { includeFields?: string[]; } +interface FinderAttributes { + title?: string; + type: string; +} + interface SavedObjectFinderState { items: Array<{ title: string | null; - id: SimpleSavedObject['id']; - type: SimpleSavedObject['type']; - savedObject: SimpleSavedObject; + id: SimpleSavedObject['id']; + type: SimpleSavedObject['type']; + savedObject: SimpleSavedObject; }>; query: string; isFetchingItems: boolean; @@ -78,13 +82,13 @@ interface SavedObjectFinderState { interface BaseSavedObjectFinder { onChoose?: ( - id: SimpleSavedObject['id'], - type: SimpleSavedObject['type'], + id: SimpleSavedObject['id'], + type: SimpleSavedObject['type'], name: string, - savedObject: SimpleSavedObject + savedObject: SimpleSavedObject ) => void; noItemsMessage?: React.ReactNode; - savedObjectMetaData: Array>; + savedObjectMetaData: Array>; showFilter?: boolean; } @@ -128,7 +132,7 @@ class SavedObjectFinderUi extends React.Component< .reduce((allFields, currentFields) => allFields.concat(currentFields), ['title']); const perPage = this.props.uiSettings.get('savedObjects:listingLimit'); - const resp = await this.props.savedObjects.client.find({ + const resp = await this.props.savedObjects.client.find({ type: Object.keys(metaDataMap), fields: [...new Set(fields)], search: query ? `${query}*` : undefined, @@ -163,6 +167,7 @@ class SavedObjectFinderUi extends React.Component< id, type, } = savedObject; + return { title: typeof title === 'string' ? title : '', id, @@ -208,7 +213,7 @@ class SavedObjectFinderUi extends React.Component< ); } - private getSavedObjectMetaDataMap(): Record> { + private getSavedObjectMetaDataMap(): Record { return this.props.savedObjectMetaData.reduce( (map, metaData) => ({ ...map, [metaData.type]: metaData }), {} @@ -470,7 +475,7 @@ class SavedObjectFinderUi extends React.Component< currentSavedObjectMetaData || ({ getIconForSavedObject: () => 'document', - } as Pick, 'getIconForSavedObject'>) + } as Pick, 'getIconForSavedObject'>) ).getIconForSavedObject(item.savedObject); return ( >({ type: this.lowercaseType, search: search ? `${search}*` : undefined, perPage: size, diff --git a/src/plugins/share/server/routes/lib/short_url_lookup.test.ts b/src/plugins/share/server/routes/lib/short_url_lookup.test.ts index 87e2b7b726e59..2b33489eb27c9 100644 --- a/src/plugins/share/server/routes/lib/short_url_lookup.test.ts +++ b/src/plugins/share/server/routes/lib/short_url_lookup.test.ts @@ -17,9 +17,10 @@ * under the License. */ -import { shortUrlLookupProvider, ShortUrlLookupService } from './short_url_lookup'; -import { SavedObjectsClientContract, Logger } from 'kibana/server'; -import { SavedObjectsClient } from '../../../../../core/server'; +import { shortUrlLookupProvider, ShortUrlLookupService, UrlAttributes } from './short_url_lookup'; +import { SavedObjectsClientContract, SavedObject } from 'kibana/server'; + +import { savedObjectsClientMock, loggingServiceMock } from '../../../../../core/server/mocks'; describe('shortUrlLookupProvider', () => { const ID = 'bf00ad16941fc51420f91a93428b27a0'; @@ -31,15 +32,10 @@ describe('shortUrlLookupProvider', () => { let shortUrl: ShortUrlLookupService; beforeEach(() => { - savedObjects = ({ - get: jest.fn(), - create: jest.fn(() => Promise.resolve({ id: ID })), - update: jest.fn(), - errors: SavedObjectsClient.errors, - } as unknown) as jest.Mocked; - + savedObjects = savedObjectsClientMock.create(); + savedObjects.create.mockResolvedValue({ id: ID } as SavedObject); deps = { savedObjects }; - shortUrl = shortUrlLookupProvider({ logger: ({ warn: () => {} } as unknown) as Logger }); + shortUrl = shortUrlLookupProvider({ logger: loggingServiceMock.create().get() }); }); describe('generateUrlId', () => { @@ -55,13 +51,13 @@ describe('shortUrlLookupProvider', () => { const [type, attributes, options] = savedObjects.create.mock.calls[0]; expect(type).toEqual(TYPE); - expect(Object.keys(attributes).sort()).toEqual([ + expect(Object.keys(attributes as UrlAttributes).sort()).toEqual([ 'accessCount', 'accessDate', 'createDate', 'url', ]); - expect(attributes.url).toEqual(URL); + expect((attributes as UrlAttributes).url).toEqual(URL); expect(options!.id).toEqual(ID); }); @@ -72,13 +68,13 @@ describe('shortUrlLookupProvider', () => { const [type, attributes] = savedObjects.create.mock.calls[0]; expect(type).toEqual(TYPE); - expect(Object.keys(attributes).sort()).toEqual([ + expect(Object.keys(attributes as UrlAttributes).sort()).toEqual([ 'accessCount', 'accessDate', 'createDate', 'url', ]); - expect(attributes.url).toEqual(URL); + expect((attributes as UrlAttributes).url).toEqual(URL); }); it('gracefully handles version conflict', async () => { @@ -119,7 +115,7 @@ describe('shortUrlLookupProvider', () => { expect(type).toEqual(TYPE); expect(id).toEqual(ID); expect(Object.keys(attributes).sort()).toEqual(['accessCount', 'accessDate']); - expect(attributes.accessCount).toEqual(3); + expect((attributes as UrlAttributes).accessCount).toEqual(3); }); }); }); diff --git a/src/plugins/share/server/routes/lib/short_url_lookup.ts b/src/plugins/share/server/routes/lib/short_url_lookup.ts index 0d8a9c86621de..65fa33a940fac 100644 --- a/src/plugins/share/server/routes/lib/short_url_lookup.ts +++ b/src/plugins/share/server/routes/lib/short_url_lookup.ts @@ -27,13 +27,20 @@ export interface ShortUrlLookupService { getUrl(url: string, deps: { savedObjects: SavedObjectsClientContract }): Promise; } +export interface UrlAttributes { + url: string; + accessCount: number; + createDate: number; + accessDate: number; +} + export function shortUrlLookupProvider({ logger }: { logger: Logger }): ShortUrlLookupService { async function updateMetadata( - doc: SavedObject, + doc: SavedObject, { savedObjects }: { savedObjects: SavedObjectsClientContract } ) { try { - await savedObjects.update('url', doc.id, { + await savedObjects.update('url', doc.id, { accessDate: new Date().valueOf(), accessCount: get(doc, 'attributes.accessCount', 0) + 1, }); @@ -53,7 +60,7 @@ export function shortUrlLookupProvider({ logger }: { logger: Logger }): ShortUrl const { isConflictError } = savedObjects.errors; try { - const doc = await savedObjects.create( + const doc = await savedObjects.create( 'url', { url, @@ -75,7 +82,7 @@ export function shortUrlLookupProvider({ logger }: { logger: Logger }): ShortUrl }, async getUrl(id, { savedObjects }) { - const doc = await savedObjects.get('url', id); + const doc = await savedObjects.get('url', id); updateMetadata(doc, { savedObjects }); return doc.attributes.url; diff --git a/x-pack/legacy/plugins/canvas/public/lib/es_service.ts b/x-pack/legacy/plugins/canvas/public/lib/es_service.ts index 2fa1bf94ad669..32f4fe041423c 100644 --- a/x-pack/legacy/plugins/canvas/public/lib/es_service.ts +++ b/x-pack/legacy/plugins/canvas/public/lib/es_service.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { IndexPatternAttributes } from 'src/plugins/data/public'; + import { API_ROUTE } from '../../common/lib/constants'; // @ts-ignore untyped local import { fetch } from '../../common/lib/fetch'; @@ -44,7 +46,7 @@ export const getFields = (index = '_all') => { export const getIndices = () => getSavedObjectsClient() - .find({ + .find({ type: 'index-pattern', fields: ['title'], searchFields: ['title'], @@ -62,7 +64,7 @@ export const getDefaultIndex = () => { return defaultIndexId ? getSavedObjectsClient() - .get('index-pattern', defaultIndexId) + .get('index-pattern', defaultIndexId) .then(defaultIndex => defaultIndex.attributes.title) .catch(err => notify.error(err, { title: strings.getDefaultIndexFetchErrorMessage() })) : Promise.resolve(''); diff --git a/x-pack/legacy/plugins/graph/public/services/persistence/saved_workspace_loader.ts b/x-pack/legacy/plugins/graph/public/services/persistence/saved_workspace_loader.ts index 184fbc01eb96f..d9bb119006e78 100644 --- a/x-pack/legacy/plugins/graph/public/services/persistence/saved_workspace_loader.ts +++ b/x-pack/legacy/plugins/graph/public/services/persistence/saved_workspace_loader.ts @@ -52,7 +52,7 @@ export function createSavedWorkspacesLoader( }, find: (searchString: string, size: number = 100) => { return savedObjectsClient - .find({ + .find>({ type: SavedWorkspace.type, search: searchString ? `${searchString}*` : undefined, perPage: size, diff --git a/x-pack/legacy/plugins/ml/common/types/kibana.ts b/x-pack/legacy/plugins/ml/common/types/kibana.ts index d647bd882162b..4a2edfebd1bac 100644 --- a/x-pack/legacy/plugins/ml/common/types/kibana.ts +++ b/x-pack/legacy/plugins/ml/common/types/kibana.ts @@ -6,7 +6,8 @@ // custom edits or fixes for default kibana types which are incomplete -import { SavedObjectAttributes, SimpleSavedObject } from 'kibana/public'; +import { SimpleSavedObject } from 'kibana/public'; +import { IndexPatternAttributes } from 'src/plugins/data/common'; export type IndexPatternTitle = string; @@ -17,8 +18,9 @@ export interface Route { k7Breadcrumbs: () => any; } -export type IndexPatternSavedObject = SimpleSavedObject; -export type SavedSearchSavedObject = SimpleSavedObject; +export type IndexPatternSavedObject = SimpleSavedObject; +// TODO define saved object type +export type SavedSearchSavedObject = SimpleSavedObject; export function isSavedSearchSavedObject( ss: SavedSearchSavedObject | null diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/resolvers.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/resolvers.ts index fa0ed34dca622..9c60b84b16bdf 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/resolvers.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/resolvers.ts @@ -61,7 +61,7 @@ export const checkForSavedObjects = async (objects: KibanaObjects): Promise { const acc = await prevPromise; - const { savedObjects } = await savedObjectsClient.find({ + const { savedObjects } = await savedObjectsClient.find({ type, perPage: 1000, }); diff --git a/x-pack/legacy/plugins/ml/public/application/util/index_utils.ts b/x-pack/legacy/plugins/ml/public/application/util/index_utils.ts index 88b56b2329ae6..220d707ddd665 100644 --- a/x-pack/legacy/plugins/ml/public/application/util/index_utils.ts +++ b/x-pack/legacy/plugins/ml/public/application/util/index_utils.ts @@ -5,11 +5,12 @@ */ import { i18n } from '@kbn/i18n'; -import { Query } from 'src/plugins/data/public'; import { IndexPattern, IIndexPattern, IndexPatternsContract, + Query, + IndexPatternAttributes, } from '../../../../../../../src/plugins/data/public'; import { getToastNotifications, getSavedObjectsClient } from './dependency_cache'; import { IndexPatternSavedObject, SavedSearchSavedObject } from '../../../common/types/kibana'; @@ -22,7 +23,7 @@ export function loadIndexPatterns(indexPatterns: IndexPatternsContract) { indexPatternsContract = indexPatterns; const savedObjectsClient = getSavedObjectsClient(); return savedObjectsClient - .find({ + .find({ type: 'index-pattern', fields: ['id', 'title', 'type', 'fields'], perPage: 10000, diff --git a/x-pack/legacy/plugins/ml/server/models/data_recognizer/data_recognizer.ts b/x-pack/legacy/plugins/ml/server/models/data_recognizer/data_recognizer.ts index b62e44c299a2d..553de75e38e05 100644 --- a/x-pack/legacy/plugins/ml/server/models/data_recognizer/data_recognizer.ts +++ b/x-pack/legacy/plugins/ml/server/models/data_recognizer/data_recognizer.ts @@ -8,6 +8,7 @@ import fs from 'fs'; import Boom from 'boom'; import numeral from '@elastic/numeral'; import { CallAPIOptions, RequestHandlerContext, SavedObjectsClientContract } from 'kibana/server'; +import { IndexPatternAttributes } from 'src/plugins/data/server'; import { merge } from 'lodash'; import { MlJob } from '../../../common/types/jobs'; import { @@ -532,7 +533,10 @@ export class DataRecognizer { } async loadIndexPatterns() { - return await this.savedObjectsClient.find({ type: 'index-pattern', perPage: 1000 }); + return await this.savedObjectsClient.find({ + type: 'index-pattern', + perPage: 1000, + }); } // returns a id based on an index pattern name @@ -620,7 +624,8 @@ export class DataRecognizer { // find all existing savedObjects for a given type loadExistingSavedObjects(type: string) { - return this.savedObjectsClient.find({ type, perPage: 1000 }); + // TODO: define saved object type + return this.savedObjectsClient.find({ type, perPage: 1000 }); } // save the savedObjects if they do not exist already diff --git a/x-pack/legacy/plugins/ml/server/models/job_service/new_job_caps/rollup.ts b/x-pack/legacy/plugins/ml/server/models/job_service/new_job_caps/rollup.ts index 11b0802192e1f..1e9ce3d8d5022 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_service/new_job_caps/rollup.ts +++ b/x-pack/legacy/plugins/ml/server/models/job_service/new_job_caps/rollup.ts @@ -5,6 +5,7 @@ */ import { SavedObject } from 'src/core/server'; +import { IndexPatternAttributes } from 'src/plugins/data/server'; import { SavedObjectsClientContract } from 'kibana/server'; import { FieldId } from '../../../../common/types/fields'; import { ES_AGGREGATION } from '../../../../common/constants/aggregation_types'; @@ -58,8 +59,8 @@ export async function rollupServiceProvider( async function loadRollupIndexPattern( indexPattern: string, savedObjectsClient: SavedObjectsClientContract -): Promise { - const resp = await savedObjectsClient.find({ +): Promise | null> { + const resp = await savedObjectsClient.find({ type: 'index-pattern', fields: ['title', 'type', 'typeMeta'], perPage: 1000, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/get_filter.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/get_filter.ts index bcf091544e52a..d1f41efdddd14 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/get_filter.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/get_filter.ts @@ -51,6 +51,15 @@ interface GetFilterArgs { index: string[] | undefined | null; } +interface QueryAttributes { + // NOTE: doesn't match Query interface + query: { + query: string; + language: string; + }; + filters: PartialFilter[]; +} + export const getFilter = async ({ filters, index, @@ -72,7 +81,10 @@ export const getFilter = async ({ if (savedId != null && index != null) { try { // try to get the saved object first - const savedObject = await services.savedObjectsClient.get('query', savedId); + const savedObject = await services.savedObjectsClient.get( + 'query', + savedId + ); return getQueryFilter( savedObject.attributes.query.query, savedObject.attributes.query.language, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/get_input_output_index.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/get_input_output_index.ts index 29d4d2182bd53..c93990e25b52b 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/get_input_output_index.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/get_input_output_index.ts @@ -16,7 +16,9 @@ export const getInputIndex = async ( if (inputIndex != null) { return inputIndex; } else { - const configuration = await services.savedObjectsClient.get('config', version); + const configuration = await services.savedObjectsClient.get<{ + 'siem:defaultIndex': string[]; + }>('config', version); if (configuration.attributes != null && configuration.attributes[DEFAULT_INDEX_KEY] != null) { return configuration.attributes[DEFAULT_INDEX_KEY]; } else { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 79337aa91b1fe..b9ac852701268 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -22,7 +22,17 @@ import { SignalRuleAlertTypeDefinition } from './types'; import { getGapBetweenRuns } from './utils'; import { ruleStatusSavedObjectType } from '../rules/saved_object_mappings'; import { IRuleSavedAttributesSavedObjectAttributes } from '../rules/types'; - +interface AlertAttributes { + enabled: boolean; + name: string; + tags: string[]; + createdBy: string; + createdAt: string; + updatedBy: string; + schedule: { + interval: string; + }; +} export const signalRulesAlertType = ({ logger, version, @@ -82,7 +92,7 @@ export const signalRulesAlertType = ({ type, } = params; // TODO: Remove this hard extraction of name once this is fixed: https://github.com/elastic/kibana/issues/50522 - const savedObject = await services.savedObjectsClient.get('alert', alertId); + const savedObject = await services.savedObjectsClient.get('alert', alertId); const ruleStatusSavedObjects = await services.savedObjectsClient.find< IRuleSavedAttributesSavedObjectAttributes >({ @@ -123,15 +133,15 @@ export const signalRulesAlertType = ({ ); } - const name: string = savedObject.attributes.name; - const tags: string[] = savedObject.attributes.tags; + const name = savedObject.attributes.name; + const tags = savedObject.attributes.tags; - const createdBy: string = savedObject.attributes.createdBy; - const createdAt: string = savedObject.attributes.createdAt; - const updatedBy: string = savedObject.attributes.updatedBy; - const updatedAt: string = savedObject.updated_at ?? ''; - const interval: string = savedObject.attributes.schedule.interval; - const enabled: boolean = savedObject.attributes.enabled; + const createdBy = savedObject.attributes.createdBy; + const createdAt = savedObject.attributes.createdAt; + const updatedBy = savedObject.attributes.updatedBy; + const updatedAt = savedObject.updated_at ?? ''; + const interval = savedObject.attributes.schedule.interval; + const enabled = savedObject.attributes.enabled; const gap = getGapBetweenRuns({ previousStartedAt: previousStartedAt != null ? moment(previousStartedAt) : null, // TODO: Remove this once previousStartedAt is no longer a string interval, diff --git a/x-pack/legacy/plugins/task_manager/server/migrations.ts b/x-pack/legacy/plugins/task_manager/server/migrations.ts index 7dce763ddf309..97c4f97f59c58 100644 --- a/x-pack/legacy/plugins/task_manager/server/migrations.ts +++ b/x-pack/legacy/plugins/task_manager/server/migrations.ts @@ -7,7 +7,7 @@ import { SavedObject } from '../../../../../src/core/server'; export const migrations = { task: { - '7.4.0': (doc: SavedObject) => ({ + '7.4.0': (doc: SavedObject>) => ({ ...doc, updated_at: new Date().toISOString(), }), @@ -18,7 +18,7 @@ export const migrations = { function moveIntervalIntoSchedule({ attributes: { interval, ...attributes }, ...doc -}: SavedObject) { +}: SavedObject>) { return { ...doc, attributes: { diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts b/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts index aba61766b5d2b..aa4cd21281e22 100644 --- a/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts @@ -9,6 +9,7 @@ import { IndexPattern, esQuery, IndexPatternsContract, + IndexPatternAttributes, } from '../../../../../../../../src/plugins/data/public'; import { matchAllQuery } from '../../common'; @@ -29,7 +30,7 @@ export function loadIndexPatterns( ) { fullIndexPatterns = indexPatterns; return savedObjectsClient - .find({ + .find({ type: 'index-pattern', fields: ['id', 'title', 'type', 'fields'], perPage: 10000, diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/usage_collector.ts b/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/usage_collector.ts index 99c0441063ce6..1d24d190fa9f2 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/usage_collector.ts +++ b/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/usage_collector.ts @@ -24,7 +24,12 @@ async function getSavedObjectAttributesFromRepo( docID: string ) { try { - return (await savedObjectsRepository.get(docType, docID)).attributes; + return ( + await savedObjectsRepository.get( + docType, + docID + ) + ).attributes; } catch (e) { return null; } diff --git a/x-pack/plugins/actions/server/actions_client.ts b/x-pack/plugins/actions/server/actions_client.ts index 7ac8ea24b5218..a06048953b62c 100644 --- a/x-pack/plugins/actions/server/actions_client.ts +++ b/x-pack/plugins/actions/server/actions_client.ts @@ -10,7 +10,7 @@ import { SavedObjectsClientContract, SavedObjectAttributes, SavedObject, -} from '../../../../src/core/server'; +} from 'src/core/server'; import { ActionTypeRegistry } from './action_type_registry'; import { validateConfig, validateSecrets } from './lib'; @@ -118,7 +118,7 @@ export class ActionsClient { * Update action */ public async update({ id, action }: UpdateOptions): Promise { - const existingObject = await this.savedObjectsClient.get('action', id); + const existingObject = await this.savedObjectsClient.get('action', id); const { actionTypeId } = existingObject.attributes; const { name, config, secrets } = action; const actionType = this.actionTypeRegistry.get(actionTypeId); @@ -144,13 +144,13 @@ export class ActionsClient { * Get an action */ public async get({ id }: { id: string }): Promise { - const result = await this.savedObjectsClient.get('action', id); + const result = await this.savedObjectsClient.get('action', id); return { id, - actionTypeId: result.attributes.actionTypeId as string, - name: result.attributes.name as string, - config: result.attributes.config as Record, + actionTypeId: result.attributes.actionTypeId, + name: result.attributes.name, + config: result.attributes.config, }; } diff --git a/x-pack/plugins/actions/server/create_execute_function.ts b/x-pack/plugins/actions/server/create_execute_function.ts index c2e8795b5f133..5316e833f33d9 100644 --- a/x-pack/plugins/actions/server/create_execute_function.ts +++ b/x-pack/plugins/actions/server/create_execute_function.ts @@ -6,7 +6,7 @@ import { SavedObjectsClientContract } from '../../../../src/core/server'; import { TaskManagerStartContract } from '../../task_manager/server'; -import { GetBasePathFunction } from './types'; +import { GetBasePathFunction, RawAction } from './types'; interface CreateExecuteFunctionOptions { taskManager: TaskManagerStartContract; @@ -59,7 +59,7 @@ export function createExecuteFunction({ }; const savedObjectsClient = getScopedSavedObjectsClient(fakeRequest); - const actionSavedObject = await savedObjectsClient.get('action', id); + const actionSavedObject = await savedObjectsClient.get('action', id); const actionTaskParamsRecord = await savedObjectsClient.create('action_task_params', { actionId: id, params, diff --git a/x-pack/plugins/alerting/server/alerts_client.ts b/x-pack/plugins/alerting/server/alerts_client.ts index ad308f819da34..9a56781aa1d7d 100644 --- a/x-pack/plugins/alerting/server/alerts_client.ts +++ b/x-pack/plugins/alerting/server/alerts_client.ts @@ -203,7 +203,7 @@ export class AlertsClient { } public async get({ id }: { id: string }): Promise { - const result = await this.savedObjectsClient.get('alert', id); + const result = await this.savedObjectsClient.get('alert', id); return this.getAlertFromRaw(result.id, result.attributes, result.updated_at, result.references); } diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.ts index 34278ee62dbc4..c2a3fbcf38069 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts @@ -5,8 +5,7 @@ */ import { pick, mapValues, omit } from 'lodash'; -import { Logger } from '../../../../../src/core/server'; -import { SavedObject } from '../../../../../src/core/server'; +import { Logger, SavedObject } from '../../../../../src/core/server'; import { TaskRunnerContext } from './task_runner_factory'; import { ConcreteTaskInstance } from '../../../../plugins/task_manager/server'; import { createExecutionHandler } from './create_execution_handler'; diff --git a/x-pack/plugins/canvas/server/routes/workpad/update.ts b/x-pack/plugins/canvas/server/routes/workpad/update.ts index 0d4809a9ee168..83b8fef48e9be 100644 --- a/x-pack/plugins/canvas/server/routes/workpad/update.ts +++ b/x-pack/plugins/canvas/server/routes/workpad/update.ts @@ -6,8 +6,7 @@ import { schema, TypeOf } from '@kbn/config-schema'; import { omit } from 'lodash'; -import { KibanaResponseFactory } from 'src/core/server'; -import { SavedObjectsClientContract } from 'src/core/server'; +import { KibanaResponseFactory, SavedObjectsClientContract } from 'src/core/server'; import { RouteInitializerDeps } from '../'; import { CANVAS_TYPE, diff --git a/x-pack/plugins/case/server/services/tags/read_tags.ts b/x-pack/plugins/case/server/services/tags/read_tags.ts index 58ab99b164cfb..da5905fe4ea35 100644 --- a/x-pack/plugins/case/server/services/tags/read_tags.ts +++ b/x-pack/plugins/case/server/services/tags/read_tags.ts @@ -52,7 +52,7 @@ export const readRawTags = async ({ page: 1, perPage, }); - const tags = await client.find({ + const tags = await client.find({ type: CASE_SAVED_OBJECT, fields: ['tags'], page: 1, diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts index 1e439b68f8c30..849bfda2bc86f 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts @@ -7,7 +7,6 @@ import uuid from 'uuid'; import { SavedObject, - SavedObjectAttributes, SavedObjectsBaseOptions, SavedObjectsBulkCreateObject, SavedObjectsBulkGetObject, @@ -42,7 +41,7 @@ export class EncryptedSavedObjectsClientWrapper implements SavedObjectsClientCon public readonly errors = options.baseClient.errors ) {} - public async create( + public async create( type: string, attributes: T = {} as T, options: SavedObjectsCreateOptions = {} @@ -66,15 +65,15 @@ export class EncryptedSavedObjectsClientWrapper implements SavedObjectsClientCon type, await this.options.service.encryptAttributes( { type, id, namespace: options.namespace }, - attributes + attributes as Record ), { ...options, id } ) - ); + ) as SavedObject; } - public async bulkCreate( - objects: SavedObjectsBulkCreateObject[], + public async bulkCreate( + objects: Array>, options?: SavedObjectsBaseOptions ) { // We encrypt attributes for every object in parallel and that can potentially exhaust libuv or @@ -101,14 +100,14 @@ export class EncryptedSavedObjectsClientWrapper implements SavedObjectsClientCon id, attributes: await this.options.service.encryptAttributes( { type: object.type, id, namespace: options && options.namespace }, - object.attributes + object.attributes as Record ), - }; + } as SavedObjectsBulkCreateObject; }) ); return this.stripEncryptedAttributesFromBulkResponse( - await this.options.baseClient.bulkCreate(encryptedObjects, options) + await this.options.baseClient.bulkCreate(encryptedObjects, options) ); } @@ -144,28 +143,28 @@ export class EncryptedSavedObjectsClientWrapper implements SavedObjectsClientCon return await this.options.baseClient.delete(type, id, options); } - public async find(options: SavedObjectsFindOptions) { + public async find(options: SavedObjectsFindOptions) { return this.stripEncryptedAttributesFromBulkResponse( - await this.options.baseClient.find(options) + await this.options.baseClient.find(options) ); } - public async bulkGet( + public async bulkGet( objects: SavedObjectsBulkGetObject[] = [], options?: SavedObjectsBaseOptions ) { return this.stripEncryptedAttributesFromBulkResponse( - await this.options.baseClient.bulkGet(objects, options) + await this.options.baseClient.bulkGet(objects, options) ); } - public async get(type: string, id: string, options?: SavedObjectsBaseOptions) { + public async get(type: string, id: string, options?: SavedObjectsBaseOptions) { return this.stripEncryptedAttributesFromResponse( - await this.options.baseClient.get(type, id, options) + await this.options.baseClient.get(type, id, options) ); } - public async update( + public async update( type: string, id: string, attributes: Partial, @@ -199,7 +198,7 @@ export class EncryptedSavedObjectsClientWrapper implements SavedObjectsClientCon if (this.options.service.isRegistered(response.type)) { response.attributes = this.options.service.stripEncryptedAttributes( response.type, - response.attributes + response.attributes as Record ); } @@ -218,7 +217,7 @@ export class EncryptedSavedObjectsClientWrapper implements SavedObjectsClientCon if (this.options.service.isRegistered(savedObject.type)) { savedObject.attributes = this.options.service.stripEncryptedAttributes( savedObject.type, - savedObject.attributes + savedObject.attributes as Record ); } } diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts index 80bd2ab7b5171..0dbdc2f3ac7e3 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts @@ -4,12 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - CoreSetup, - SavedObject, - SavedObjectAttributes, - SavedObjectsBaseOptions, -} from 'src/core/server'; +import { CoreSetup, SavedObject, SavedObjectsBaseOptions } from 'src/core/server'; import { EncryptedSavedObjectsService } from '../crypto'; import { EncryptedSavedObjectsClientWrapper } from './encrypted_saved_objects_client_wrapper'; @@ -20,7 +15,7 @@ interface SetupSavedObjectsParams { } export interface SavedObjectsSetup { - getDecryptedAsInternalUser: ( + getDecryptedAsInternalUser: ( type: string, id: string, options?: SavedObjectsBaseOptions @@ -47,7 +42,7 @@ export function setupSavedObjects({ core.savedObjects.createInternalRepository() ); return { - getDecryptedAsInternalUser: async ( + getDecryptedAsInternalUser: async ( type: string, id: string, options?: SavedObjectsBaseOptions @@ -56,10 +51,10 @@ export function setupSavedObjects({ const savedObject = await internalRepository.get(type, id, options); return { ...savedObject, - attributes: await service.decryptAttributes( + attributes: (await service.decryptAttributes( { type, id, namespace: options && options.namespace }, - savedObject.attributes - ), + savedObject.attributes as Record + )) as T, }; }, }; diff --git a/x-pack/plugins/infra/public/hooks/use_bulk_get_saved_object.tsx b/x-pack/plugins/infra/public/hooks/use_bulk_get_saved_object.tsx index 80d1b67e59798..2c553b57dcd48 100644 --- a/x-pack/plugins/infra/public/hooks/use_bulk_get_saved_object.tsx +++ b/x-pack/plugins/infra/public/hooks/use_bulk_get_saved_object.tsx @@ -5,12 +5,13 @@ */ import { useState, useCallback } from 'react'; -import { SavedObjectAttributes, SavedObjectsBatchResponse } from 'src/core/public'; +import { SavedObjectsBatchResponse } from 'src/core/public'; import { useKibana } from '../../../../../src/plugins/kibana_react/public'; export const useBulkGetSavedObject = (type: string) => { const kibana = useKibana(); - const [data, setData] = useState | null>(null); + // TODO: define saved object type + const [data, setData] = useState | null>(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); diff --git a/x-pack/plugins/lens/server/routes/existing_fields.test.ts b/x-pack/plugins/lens/server/routes/existing_fields.test.ts index 1f19671826807..9bd11b6863d93 100644 --- a/x-pack/plugins/lens/server/routes/existing_fields.test.ts +++ b/x-pack/plugins/lens/server/routes/existing_fields.test.ts @@ -91,6 +91,8 @@ describe('buildFieldList', () => { type: 'indexpattern', attributes: { title: 'testpattern', + type: 'type', + typeMeta: 'typemeta', fields: JSON.stringify([ { name: 'foo', scripted: true, lang: 'painless', script: '2+2' }, { name: 'bar' }, diff --git a/x-pack/plugins/lens/server/routes/existing_fields.ts b/x-pack/plugins/lens/server/routes/existing_fields.ts index a059e32585909..40b2766a647cf 100644 --- a/x-pack/plugins/lens/server/routes/existing_fields.ts +++ b/x-pack/plugins/lens/server/routes/existing_fields.ts @@ -9,7 +9,10 @@ import { schema } from '@kbn/config-schema'; import { IScopedClusterClient, SavedObject, RequestHandlerContext } from 'src/core/server'; import { CoreSetup } from 'src/core/server'; import { BASE_API_URL } from '../../common'; -import { IndexPatternsFetcher } from '../../../../../src/plugins/data/server'; +import { + IndexPatternsFetcher, + IndexPatternAttributes, +} from '../../../../../src/plugins/data/server'; /** * The number of docs to sample to determine field empty status. @@ -125,7 +128,10 @@ async function fetchFieldExistence({ async function fetchIndexPatternDefinition(indexPatternId: string, context: RequestHandlerContext) { const savedObjectsClient = context.core.savedObjects.client; const requestClient = context.core.elasticsearch.dataClient; - const indexPattern = await savedObjectsClient.get('index-pattern', indexPatternId); + const indexPattern = await savedObjectsClient.get( + 'index-pattern', + indexPatternId + ); const indexPatternTitle = indexPattern.attributes.title; // TODO: maybe don't use IndexPatternsFetcher at all, since we're only using it // to look up field values in the resulting documents. We can accomplish the same @@ -155,7 +161,7 @@ async function fetchIndexPatternDefinition(indexPatternId: string, context: Requ * Exported only for unit tests. */ export function buildFieldList( - indexPattern: SavedObject, + indexPattern: SavedObject, mappings: MappingResult, fieldDescriptors: FieldDescriptor[] ): Field[] { diff --git a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts index 03b1d770fa770..2209e7fb66fcb 100644 --- a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts +++ b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts @@ -5,7 +5,6 @@ */ import { - SavedObjectAttributes, SavedObjectsBaseOptions, SavedObjectsBulkCreateObject, SavedObjectsBulkGetObject, @@ -46,7 +45,7 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra this.checkSavedObjectsPrivilegesAsCurrentUser = checkSavedObjectsPrivilegesAsCurrentUser; } - public async create( + public async create( type: string, attributes: T = {} as T, options: SavedObjectsCreateOptions = {} @@ -56,8 +55,8 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra return await this.baseClient.create(type, attributes, options); } - public async bulkCreate( - objects: SavedObjectsBulkCreateObject[], + public async bulkCreate( + objects: Array>, options: SavedObjectsBaseOptions = {} ) { await this.ensureAuthorized( @@ -76,13 +75,13 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra return await this.baseClient.delete(type, id, options); } - public async find(options: SavedObjectsFindOptions) { + public async find(options: SavedObjectsFindOptions) { await this.ensureAuthorized(options.type, 'find', options.namespace, { options }); - return this.baseClient.find(options); + return this.baseClient.find(options); } - public async bulkGet( + public async bulkGet( objects: SavedObjectsBulkGetObject[] = [], options: SavedObjectsBaseOptions = {} ) { @@ -91,16 +90,16 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra options, }); - return await this.baseClient.bulkGet(objects, options); + return await this.baseClient.bulkGet(objects, options); } - public async get(type: string, id: string, options: SavedObjectsBaseOptions = {}) { + public async get(type: string, id: string, options: SavedObjectsBaseOptions = {}) { await this.ensureAuthorized(type, 'get', options.namespace, { type, id, options }); - return await this.baseClient.get(type, id, options); + return await this.baseClient.get(type, id, options); } - public async update( + public async update( type: string, id: string, attributes: Partial, @@ -116,8 +115,8 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra return await this.baseClient.update(type, id, attributes, options); } - public async bulkUpdate( - objects: SavedObjectsBulkUpdateObject[] = [], + public async bulkUpdate( + objects: Array> = [], options: SavedObjectsBaseOptions = {} ) { await this.ensureAuthorized( @@ -127,7 +126,7 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra { objects, options } ); - return await this.baseClient.bulkUpdate(objects, options); + return await this.baseClient.bulkUpdate(objects, options); } private async checkPrivileges(actions: string | string[], namespace?: string) { diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts index 62a78679175b3..534d797123940 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts @@ -5,7 +5,6 @@ */ import { - SavedObjectAttributes, SavedObjectsBaseOptions, SavedObjectsBulkCreateObject, SavedObjectsBulkGetObject, @@ -65,14 +64,14 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { * @property {string} [options.namespace] * @returns {promise} - { id, type, version, attributes } */ - public async create( + public async create( type: string, attributes: T = {} as T, options: SavedObjectsCreateOptions = {} ) { throwErrorIfNamespaceSpecified(options); - return await this.client.create(type, attributes, { + return await this.client.create(type, attributes, { ...options, namespace: spaceIdToNamespace(this.spaceId), }); @@ -87,8 +86,8 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { * @property {string} [options.namespace] * @returns {promise} - { saved_objects: [{ id, type, version, attributes, error: { message } }]} */ - public async bulkCreate( - objects: SavedObjectsBulkCreateObject[], + public async bulkCreate( + objects: Array>, options: SavedObjectsBaseOptions = {} ) { throwErrorIfNamespaceSpecified(options); @@ -133,10 +132,10 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { * @property {object} [options.hasReference] - { type, id } * @returns {promise} - { saved_objects: [{ id, type, version, attributes }], total, per_page, page } */ - public async find(options: SavedObjectsFindOptions) { + public async find(options: SavedObjectsFindOptions) { throwErrorIfNamespaceSpecified(options); - return await this.client.find({ + return await this.client.find({ ...options, type: (options.type ? coerceToArray(options.type) : this.types).filter( type => type !== 'space' @@ -159,13 +158,13 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { * { id: 'foo', type: 'index-pattern' } * ]) */ - public async bulkGet( + public async bulkGet( objects: SavedObjectsBulkGetObject[] = [], options: SavedObjectsBaseOptions = {} ) { throwErrorIfNamespaceSpecified(options); - return await this.client.bulkGet(objects, { + return await this.client.bulkGet(objects, { ...options, namespace: spaceIdToNamespace(this.spaceId), }); @@ -180,10 +179,10 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { * @property {string} [options.namespace] * @returns {promise} - { id, type, version, attributes } */ - public async get(type: string, id: string, options: SavedObjectsBaseOptions = {}) { + public async get(type: string, id: string, options: SavedObjectsBaseOptions = {}) { throwErrorIfNamespaceSpecified(options); - return await this.client.get(type, id, { + return await this.client.get(type, id, { ...options, namespace: spaceIdToNamespace(this.spaceId), }); @@ -199,7 +198,7 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { * @property {string} [options.namespace] * @returns {promise} */ - public async update( + public async update( type: string, id: string, attributes: Partial, @@ -225,8 +224,8 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { * { id: 'foo', type: 'index-pattern', attributes: {} } * ]) */ - public async bulkUpdate( - objects: SavedObjectsBulkUpdateObject[] = [], + public async bulkUpdate( + objects: Array> = [], options: SavedObjectsBaseOptions = {} ) { throwErrorIfNamespaceSpecified(options); diff --git a/x-pack/plugins/task_manager/server/task_store.test.ts b/x-pack/plugins/task_manager/server/task_store.test.ts index 6ed6ae16fa0f9..97794311fb3d2 100644 --- a/x-pack/plugins/task_manager/server/task_store.test.ts +++ b/x-pack/plugins/task_manager/server/task_store.test.ts @@ -18,11 +18,7 @@ import { } from './task'; import { StoreOpts, OwnershipClaimingOpts, TaskStore, SearchOpts } from './task_store'; import { savedObjectsRepositoryMock } from '../../../../src/core/server/mocks'; -import { - SavedObjectsSerializer, - SavedObjectTypeRegistry, - SavedObjectAttributes, -} from '../../../../src/core/server'; +import { SavedObjectsSerializer, SavedObjectTypeRegistry } from '../../../../src/core/server'; import { SavedObjectsErrorHelpers } from '../../../../src/core/server/saved_objects/service/lib/errors'; import { asTaskClaimEvent, TaskEvent } from './task_events'; import { asOk, asErr } from './lib/result_type'; @@ -64,15 +60,13 @@ describe('TaskStore', () => { describe('schedule', () => { async function testSchedule(task: TaskInstance) { const callCluster = jest.fn(); - savedObjectsClient.create.mockImplementation( - async (type: string, attributes: SavedObjectAttributes) => ({ - id: 'testid', - type, - attributes, - references: [], - version: '123', - }) - ); + savedObjectsClient.create.mockImplementation(async (type: string, attributes: any) => ({ + id: 'testid', + type, + attributes, + references: [], + version: '123', + })); const store = new TaskStore({ index: 'tasky', taskManagerId: '', @@ -155,14 +149,14 @@ describe('TaskStore', () => { test('sets runAt to now if not specified', async () => { await testSchedule({ taskType: 'dernstraight', params: {}, state: {} }); expect(savedObjectsClient.create).toHaveBeenCalledTimes(1); - const attributes = savedObjectsClient.create.mock.calls[0][1]; + const attributes: any = savedObjectsClient.create.mock.calls[0][1]; expect(new Date(attributes.runAt as string).getTime()).toEqual(mockedDate.getTime()); }); test('ensures params and state are not null', async () => { await testSchedule({ taskType: 'yawn' } as any); expect(savedObjectsClient.create).toHaveBeenCalledTimes(1); - const attributes = savedObjectsClient.create.mock.calls[0][1]; + const attributes: any = savedObjectsClient.create.mock.calls[0][1]; expect(attributes.params).toEqual('{}'); expect(attributes.state).toEqual('{}'); }); @@ -751,7 +745,7 @@ if (doc['task.runAt'].size()!=0) { }; savedObjectsClient.update.mockImplementation( - async (type: string, id: string, attributes: SavedObjectAttributes) => { + async (type: string, id: string, attributes: any) => { return { id, type, diff --git a/x-pack/plugins/task_manager/server/task_store.ts b/x-pack/plugins/task_manager/server/task_store.ts index 3915eeffc5519..0e487386eb04d 100644 --- a/x-pack/plugins/task_manager/server/task_store.ts +++ b/x-pack/plugins/task_manager/server/task_store.ts @@ -428,7 +428,8 @@ function taskInstanceToAttributes(doc: TaskInstance): SavedObjectAttributes { } export function savedObjectToConcreteTaskInstance( - savedObject: Omit + // TODO: define saved object type + savedObject: Omit, 'references'> ): ConcreteTaskInstance { return { ...savedObject.attributes, diff --git a/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts b/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts index 071067ffa85cb..3529d8f3ae9c9 100644 --- a/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts +++ b/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts @@ -59,7 +59,9 @@ export function resolveCopyToSpaceConflictsSuite( .then((response: any) => response.body); }; - const getObjectsAtSpace = async (spaceId: string): Promise<[SavedObject, SavedObject]> => { + const getObjectsAtSpace = async ( + spaceId: string + ): Promise<[SavedObject, SavedObject]> => { const dashboard = await getDashboardAtSpace(spaceId); const visualization = await getVisualizationAtSpace(spaceId); return [dashboard, visualization]; From 1eb01760365030f1793f086dea2f32a28a15a125 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 21 Feb 2020 13:58:54 -0800 Subject: [PATCH 014/123] Added UI support for the default action group for Alert Type Model (#57603) * Added UI support for the default action group for Alert Type Model * Fixed set default on alert type select * Fixed type check * Moved setting of default alert type to the server api * Added default value for actionGroups if it is empty in register alert type functions * Fixed type check * Fixed due to comments aed89377b9 Yuliia Naumenko Feb 20, 2020 at 12:40 PM * Renamed defaultActionGroup to defaultActionGroupId * Fixed failing tests --- .../server/alerts/license_expiration.ts | 1 + .../signals/signal_rule_alert_type.ts | 1 + x-pack/plugins/alerting/common/index.ts | 5 ++ .../server/alert_type_registry.test.ts | 50 ++++++++++++++++--- .../alerting/server/alert_type_registry.ts | 1 + .../alerting/server/alerts_client.test.ts | 12 ++++- x-pack/plugins/alerting/server/index.ts | 1 + .../lib/validate_alert_type_params.test.ts | 24 +++++++-- .../server/routes/list_alert_types.test.ts | 24 +++++++-- .../create_execution_handler.test.ts | 1 + .../server/task_runner/task_runner.test.ts | 1 + .../task_runner/task_runner_factory.test.ts | 1 + x-pack/plugins/alerting/server/types.ts | 8 +-- .../public/application/lib/alert_api.test.ts | 1 + .../sections/alert_add/alert_form.test.tsx | 1 + .../sections/alert_add/alert_form.tsx | 40 ++++++++------- .../components/alert_details.test.tsx | 16 ++++++ .../triggers_actions_ui/public/types.ts | 8 +-- .../common/fixtures/plugins/alerts/index.ts | 35 +++++++++++-- .../tests/alerting/list_alert_types.ts | 1 + .../tests/alerting/list_alert_types.ts | 1 + .../fixtures/plugins/alerts/index.ts | 1 + 22 files changed, 190 insertions(+), 44 deletions(-) diff --git a/x-pack/legacy/plugins/monitoring/server/alerts/license_expiration.ts b/x-pack/legacy/plugins/monitoring/server/alerts/license_expiration.ts index f968e90f70b2d..9ef19e58bada7 100644 --- a/x-pack/legacy/plugins/monitoring/server/alerts/license_expiration.ts +++ b/x-pack/legacy/plugins/monitoring/server/alerts/license_expiration.ts @@ -54,6 +54,7 @@ export const getLicenseExpiration = ( }), }, ], + defaultActionGroupId: 'default', async executor({ services, params, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index b9ac852701268..f7fabfb980195 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -51,6 +51,7 @@ export const signalRulesAlertType = ({ }), }, ], + defaultActionGroupId: 'default', validate: { params: schema.object({ description: schema.string(), diff --git a/x-pack/plugins/alerting/common/index.ts b/x-pack/plugins/alerting/common/index.ts index 03b3487f10f1d..8c6969cded85a 100644 --- a/x-pack/plugins/alerting/common/index.ts +++ b/x-pack/plugins/alerting/common/index.ts @@ -7,3 +7,8 @@ export * from './alert'; export * from './alert_instance'; export * from './alert_task_instance'; + +export interface ActionGroup { + id: string; + name: string; +} diff --git a/x-pack/plugins/alerting/server/alert_type_registry.test.ts b/x-pack/plugins/alerting/server/alert_type_registry.test.ts index 1a820d55af8a4..f4749772c7004 100644 --- a/x-pack/plugins/alerting/server/alert_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/alert_type_registry.test.ts @@ -27,7 +27,13 @@ describe('has()', () => { registry.register({ id: 'foo', name: 'Foo', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', executor: jest.fn(), }); expect(registry.has('foo')).toEqual(true); @@ -39,7 +45,13 @@ describe('register()', () => { const alertType = { id: 'test', name: 'Test', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', executor: jest.fn(), }; // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -64,14 +76,26 @@ describe('register()', () => { registry.register({ id: 'test', name: 'Test', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', executor: jest.fn(), }); expect(() => registry.register({ id: 'test', name: 'Test', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', executor: jest.fn(), }) ).toThrowErrorMatchingInlineSnapshot(`"Alert type \\"test\\" is already registered."`); @@ -84,13 +108,25 @@ describe('get()', () => { registry.register({ id: 'test', name: 'Test', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', executor: jest.fn(), }); const alertType = registry.get('test'); expect(alertType).toMatchInlineSnapshot(` Object { - "actionGroups": Array [], + "actionGroups": Array [ + Object { + "id": "default", + "name": "Default", + }, + ], + "defaultActionGroupId": "default", "executor": [MockFunction], "id": "test", "name": "Test", @@ -124,6 +160,7 @@ describe('list()', () => { name: 'Test Action Group', }, ], + defaultActionGroupId: 'testActionGroup', executor: jest.fn(), }); const result = registry.list(); @@ -136,6 +173,7 @@ describe('list()', () => { "name": "Test Action Group", }, ], + "defaultActionGroupId": "testActionGroup", "id": "test", "name": "Test", }, diff --git a/x-pack/plugins/alerting/server/alert_type_registry.ts b/x-pack/plugins/alerting/server/alert_type_registry.ts index b0976d67c70a0..d9045fb986745 100644 --- a/x-pack/plugins/alerting/server/alert_type_registry.ts +++ b/x-pack/plugins/alerting/server/alert_type_registry.ts @@ -70,6 +70,7 @@ export class AlertTypeRegistry { id: alertTypeId, name: alertType.name, actionGroups: alertType.actionGroups, + defaultActionGroupId: alertType.defaultActionGroupId, })); } } diff --git a/x-pack/plugins/alerting/server/alerts_client.test.ts b/x-pack/plugins/alerting/server/alerts_client.test.ts index 629bd05a8c76a..ed6e7562e3acd 100644 --- a/x-pack/plugins/alerting/server/alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client.test.ts @@ -87,6 +87,7 @@ describe('create()', () => { id: '123', name: 'Test', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', async executor() {}, }); }); @@ -522,7 +523,13 @@ describe('create()', () => { alertTypeRegistry.get.mockReturnValue({ id: '123', name: 'Test', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', validate: { params: schema.object({ param1: schema.string(), @@ -1885,6 +1892,7 @@ describe('update()', () => { id: '123', name: 'Test', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', async executor() {}, }); }); @@ -2415,6 +2423,7 @@ describe('update()', () => { id: '123', name: 'Test', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', validate: { params: schema.object({ param1: schema.string(), @@ -2647,6 +2656,7 @@ describe('update()', () => { id: '123', name: 'Test', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', async executor() {}, }); savedObjectsClient.bulkGet.mockResolvedValueOnce({ diff --git a/x-pack/plugins/alerting/server/index.ts b/x-pack/plugins/alerting/server/index.ts index 58b77f0f510f7..727e38d9ba56b 100644 --- a/x-pack/plugins/alerting/server/index.ts +++ b/x-pack/plugins/alerting/server/index.ts @@ -12,6 +12,7 @@ export type AlertsClient = PublicMethodsOf; export { AlertType, + ActionGroup, AlertingPlugin, AlertExecutorOptions, AlertActionParams, diff --git a/x-pack/plugins/alerting/server/lib/validate_alert_type_params.test.ts b/x-pack/plugins/alerting/server/lib/validate_alert_type_params.test.ts index e9a61354001f1..67820e44f567e 100644 --- a/x-pack/plugins/alerting/server/lib/validate_alert_type_params.test.ts +++ b/x-pack/plugins/alerting/server/lib/validate_alert_type_params.test.ts @@ -12,7 +12,13 @@ test('should return passed in params when validation not defined', () => { { id: 'my-alert-type', name: 'My description', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', async executor() {}, }, { @@ -27,7 +33,13 @@ test('should validate and apply defaults when params is valid', () => { { id: 'my-alert-type', name: 'My description', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', validate: { params: schema.object({ param1: schema.string(), @@ -50,7 +62,13 @@ test('should validate and throw error when params is invalid', () => { { id: 'my-alert-type', name: 'My description', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', validate: { params: schema.object({ param1: schema.string(), diff --git a/x-pack/plugins/alerting/server/routes/list_alert_types.test.ts b/x-pack/plugins/alerting/server/routes/list_alert_types.test.ts index 3e9f57d55122d..96ee8c5717453 100644 --- a/x-pack/plugins/alerting/server/routes/list_alert_types.test.ts +++ b/x-pack/plugins/alerting/server/routes/list_alert_types.test.ts @@ -40,7 +40,13 @@ describe('listAlertTypesRoute', () => { { id: '1', name: 'name', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', }, ]; @@ -50,7 +56,13 @@ describe('listAlertTypesRoute', () => { Object { "body": Array [ Object { - "actionGroups": Array [], + "actionGroups": Array [ + Object { + "id": "default", + "name": "Default", + }, + ], + "defaultActionGroupId": "default", "id": "1", "name": "name", }, @@ -128,7 +140,13 @@ describe('listAlertTypesRoute', () => { { id: '1', name: 'name', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', }, ]; diff --git a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts index 1b3a9ed8d7b06..32299680a1f8c 100644 --- a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts @@ -15,6 +15,7 @@ const alertType: AlertType = { { id: 'default', name: 'Default' }, { id: 'other-group', name: 'Other Group' }, ], + defaultActionGroupId: 'default', executor: jest.fn(), }; diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index af0e7b658240a..d1bc0de3ae0e2 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -17,6 +17,7 @@ const alertType = { id: 'test', name: 'My test alert', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', executor: jest.fn(), }; let fakeTimer: sinon.SinonFakeTimers; diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts index 4dad46ef32f21..f885b0bdbd046 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts @@ -14,6 +14,7 @@ const alertType = { id: 'test', name: 'My test alert', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', executor: jest.fn(), }; let fakeTimer: sinon.SinonFakeTimers; diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index 202a73f076859..90bc7996729a6 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -8,7 +8,7 @@ import { AlertInstance } from './alert_instance'; import { AlertTypeRegistry as OrigAlertTypeRegistry } from './alert_type_registry'; import { PluginSetupContract, PluginStartContract } from './plugin'; import { SavedObjectAttributes, SavedObjectsClientContract } from '../../../../src/core/server'; -import { Alert, AlertActionParams } from '../common'; +import { Alert, AlertActionParams, ActionGroup } from '../common'; import { AlertsClient } from './alerts_client'; export * from '../common'; @@ -52,11 +52,6 @@ export interface AlertExecutorOptions { updatedBy: string | null; } -export interface ActionGroup { - id: string; - name: string; -} - export interface AlertType { id: string; name: string; @@ -64,6 +59,7 @@ export interface AlertType { params?: { validate: (object: any) => any }; }; actionGroups: ActionGroup[]; + defaultActionGroupId: ActionGroup['id']; executor: ({ services, params, state }: AlertExecutorOptions) => Promise; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts index 93a46862f4cd2..1e53e7d983848 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts @@ -40,6 +40,7 @@ describe('loadAlertTypes', () => { name: 'Test', actionVariables: ['var1'], actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', }, ]; http.get.mockResolvedValueOnce(resolvedValue); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_add/alert_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_add/alert_form.test.tsx index ce524ed8178ee..aa71621f1a914 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_add/alert_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_add/alert_form.test.tsx @@ -158,6 +158,7 @@ describe('alert_form', () => { alertTypeRegistry.has.mockReturnValue(true); actionTypeRegistry.list.mockReturnValue([actionType]); actionTypeRegistry.has.mockReturnValue(true); + actionTypeRegistry.get.mockReturnValue(actionType); const initialAlert = ({ name: 'test', diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_add/alert_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_add/alert_form.tsx index 95c049f32436a..18dc88f54e907 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_add/alert_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_add/alert_form.tsx @@ -40,7 +40,6 @@ import { ActionTypeIndex, ActionConnector, AlertTypeIndex, - ActionGroup, } from '../../../types'; import { SectionLoading } from '../../components/section_loading'; import { ConnectorAddModal } from '../action_connector_form/connector_add_modal'; @@ -119,7 +118,7 @@ export const AlertForm = ({ const [alertThrottleUnit, setAlertThrottleUnit] = useState('m'); const [isAddActionPanelOpen, setIsAddActionPanelOpen] = useState(true); const [connectors, setConnectors] = useState([]); - const [defaultActionGroup, setDefaultActionGroup] = useState(undefined); + const [defaultActionGroupId, setDefaultActionGroupId] = useState(undefined); const [activeActionItem, setActiveActionItem] = useState( undefined ); @@ -166,13 +165,14 @@ export const AlertForm = ({ ], name: 'threshold', actionVariables: ['ctx.metadata.name', 'ctx.metadata.test'], + defaultActionGroupId: 'alert', }); const index: AlertTypeIndex = {}; for (const alertTypeItem of alertTypes) { index[alertTypeItem.id] = alertTypeItem; } - if (alert.alertTypeId) { - setDefaultActionGroup(index[alert.alertTypeId].actionGroups[0]); + if (alert.alertTypeId && index[alert.alertTypeId]) { + setDefaultActionGroupId(index[alert.alertTypeId].defaultActionGroupId); } setAlertTypesIndex(index); } catch (e) { @@ -251,6 +251,14 @@ export const AlertForm = ({ : null; function addActionType(actionTypeModel: ActionTypeModel) { + if (!defaultActionGroupId) { + toastNotifications!.addDanger({ + title: i18n.translate('xpack.triggersActionsUI.sections.alertForm.unableToAddAction', { + defaultMessage: 'Unable to add action, because default action group is not defined', + }), + }); + return; + } setIsAddActionPanelOpen(false); const actionTypeConnectors = connectors.filter( field => field.actionTypeId === actionTypeModel.id @@ -266,7 +274,7 @@ export const AlertForm = ({ alert.actions.push({ id: '', actionTypeId: actionTypeModel.id, - group: defaultActionGroup?.id ?? 'Alert', + group: defaultActionGroupId, params: {}, }); setActionProperty('id', freeConnectors[0].id, alert.actions.length - 1); @@ -278,7 +286,7 @@ export const AlertForm = ({ alert.actions.push({ id: '', actionTypeId: actionTypeModel.id, - group: defaultActionGroup?.id ?? 'Alert', + group: defaultActionGroupId, params: {}, }); setActionProperty('id', alert.actions.length, alert.actions.length - 1); @@ -294,12 +302,8 @@ export const AlertForm = ({ onClick={() => { setAlertProperty('alertTypeId', item.id); setAlertTypeModel(item); - if ( - alertTypesIndex && - alertTypesIndex[item.id] && - alertTypesIndex[item.id].actionGroups.length > 0 - ) { - setDefaultActionGroup(alertTypesIndex[item.id].actionGroups[0]); + if (alertTypesIndex && alertTypesIndex[item.id]) { + setDefaultActionGroupId(alertTypesIndex[item.id].defaultActionGroupId); } }} > @@ -356,7 +360,7 @@ export const AlertForm = ({ id, })); const actionTypeRegisterd = actionTypeRegistry.get(actionConnector.actionTypeId); - if (actionTypeRegisterd === null || actionItem.group !== defaultActionGroup?.id) return null; + if (!actionTypeRegisterd || actionItem.group !== defaultActionGroupId) return null; const ParamsFieldsComponent = actionTypeRegisterd.actionParamsFields; const actionParamsErrors: { errors: IErrorObject } = Object.keys(actionsErrors).length > 0 ? actionsErrors[actionItem.id] : { errors: {} }; @@ -368,7 +372,7 @@ export const AlertForm = ({ id={index.toString()} className="euiAccordionForm" buttonContentClassName="euiAccordionForm__button" - data-test-subj="alertActionAccordion" + data-test-subj={`alertActionAccordion-${defaultActionGroupId}`} buttonContent={ @@ -465,7 +469,9 @@ export const AlertForm = ({ errors={actionParamsErrors.errors} editAction={setActionParamsProperty} messageVariables={ - alertTypesIndex ? alertTypesIndex[alert.alertTypeId].actionVariables : undefined + alertTypesIndex && alertTypesIndex[alert.alertTypeId] + ? alertTypesIndex[alert.alertTypeId].actionVariables + : undefined } defaultMessage={alertTypeModel?.defaultActionMessage ?? undefined} /> @@ -479,7 +485,7 @@ export const AlertForm = ({ ? actionTypesIndex[actionItem.actionTypeId].name : actionItem.actionTypeId; const actionTypeRegisterd = actionTypeRegistry.get(actionItem.actionTypeId); - if (actionTypeRegisterd === null || actionItem.group !== defaultActionGroup?.id) return null; + if (!actionTypeRegisterd || actionItem.group !== defaultActionGroupId) return null; return ( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx index c67954bdc44fd..d2cf2decc4a16 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx @@ -45,6 +45,7 @@ describe('alert_details', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -65,6 +66,7 @@ describe('alert_details', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -92,6 +94,7 @@ describe('alert_details', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -141,6 +144,7 @@ describe('alert_details', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; const actionTypes: ActionType[] = [ @@ -191,6 +195,7 @@ describe('alert_details', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -215,6 +220,7 @@ describe('alert_details', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -239,6 +245,7 @@ describe('alert_details', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -268,6 +275,7 @@ describe('enable button', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -293,6 +301,7 @@ describe('enable button', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -318,6 +327,7 @@ describe('enable button', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -352,6 +362,7 @@ describe('enable button', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -389,6 +400,7 @@ describe('mute button', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -415,6 +427,7 @@ describe('mute button', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -441,6 +454,7 @@ describe('mute button', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -476,6 +490,7 @@ describe('mute button', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; @@ -511,6 +526,7 @@ describe('mute button', () => { id: '.noop', name: 'No Op', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', actionVariables: [], }; diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index aa1d3d068ed77..2119c08bedc31 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { ActionGroup } from '../../alerting/common'; import { ActionType } from '../../actions/common'; import { TypeRegistry } from './application/type_registry'; import { @@ -70,17 +71,16 @@ export interface ActionConnectorTableItem extends ActionConnector { actionType: ActionType['name']; } -export interface ActionGroup { - id: string; - name: string; -} export interface AlertType { id: string; name: string; actionGroups: ActionGroup[]; actionVariables: string[]; + defaultActionGroupId: ActionGroup['id']; } +export type SanitizedAlertType = Omit; + export type AlertWithoutId = Omit; export interface AlertTableItem extends Alert { diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts index b06e0c9e0f8cd..2e7674f2b3eb7 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts @@ -206,6 +206,7 @@ export default function(kibana: any) { { id: 'default', name: 'Default' }, { id: 'other', name: 'Other' }, ], + defaultActionGroupId: 'default', async executor(alertExecutorOptions: AlertExecutorOptions) { const { services, @@ -260,6 +261,7 @@ export default function(kibana: any) { { id: 'default', name: 'Default' }, { id: 'other', name: 'Other' }, ], + defaultActionGroupId: 'default', async executor(alertExecutorOptions: AlertExecutorOptions) { const { services, state } = alertExecutorOptions; const group = 'default'; @@ -281,7 +283,13 @@ export default function(kibana: any) { const neverFiringAlertType: AlertType = { id: 'test.never-firing', name: 'Test: Never firing', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', async executor({ services, params, state }: AlertExecutorOptions) { await services.callCluster('index', { index: params.index, @@ -301,7 +309,13 @@ export default function(kibana: any) { const failingAlertType: AlertType = { id: 'test.failing', name: 'Test: Failing', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', async executor({ services, params, state }: AlertExecutorOptions) { await services.callCluster('index', { index: params.index, @@ -319,7 +333,13 @@ export default function(kibana: any) { const authorizationAlertType: AlertType = { id: 'test.authorization', name: 'Test: Authorization', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', validate: { params: schema.object({ callClusterAuthorizationIndex: schema.string(), @@ -378,7 +398,13 @@ export default function(kibana: any) { const validationAlertType: AlertType = { id: 'test.validation', name: 'Test: Validation', - actionGroups: [], + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', validate: { params: schema.object({ param1: schema.string(), @@ -390,6 +416,7 @@ export default function(kibana: any) { id: 'test.noop', name: 'Test: Noop', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', async executor({ services, params, state }: AlertExecutorOptions) {}, }; server.newPlatform.setup.plugins.alerting.registerType(alwaysFiringAlertType); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/list_alert_types.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/list_alert_types.ts index 517a60f77849e..30c1548b7db2a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/list_alert_types.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/list_alert_types.ts @@ -41,6 +41,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { ); expect(fixtureAlertType).to.eql({ actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', id: 'test.noop', name: 'Test: Noop', }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/list_alert_types.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/list_alert_types.ts index 55570744f6af9..590de1ea7ce0b 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/list_alert_types.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/list_alert_types.ts @@ -21,6 +21,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) { const fixtureAlertType = response.body.find((alertType: any) => alertType.id === 'test.noop'); expect(fixtureAlertType).to.eql({ actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', id: 'test.noop', name: 'Test: Noop', }); diff --git a/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/index.ts b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/index.ts index 678707af40bae..9069044b83ed9 100644 --- a/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/index.ts +++ b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/index.ts @@ -23,6 +23,7 @@ function createNoopAlertType(setupContract: any) { id: 'test.noop', name: 'Test: Noop', actionGroups: [{ id: 'default', name: 'Default' }], + defaultActionGroupId: 'default', async executor() {}, }; setupContract.registerType(noopAlertType); From 5fefb76a261f41e04ad263bdd44fde72ab2f2496 Mon Sep 17 00:00:00 2001 From: Caroline Horn <549577+cchaos@users.noreply.github.com> Date: Fri, 21 Feb 2020 18:28:53 -0500 Subject: [PATCH 015/123] Use EuiTokens for ES field types (#57911) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [FieldIcon] Refactor to extend EuiToken and props * [Add to FieldIcon] Export props * [Graph] Updated instances of FieldIcon * [Maps] Update FieldIcon instance * [Lens] Update FieldIcon usage * [Discover] Update FieldIcon usage * Remove comment * [Lens] Delete unused files * [Graph] Fix alignments * More cleanup * Fixing snaps * [Lens] Removing method `getColorForDataType` The method no longer returns the correct color and EuiProgress doesn’t currently support all the colors from the token map. @cchaos will follow up with a PR to address the coloring of the field data charts. Right now they will fallback to pink for progress and default for charts. * [Maps] Fixing implementations of FieldIcon * [Graph] Using css utility class instead of custom class * Snap * Fix css to use var --- .../public/discover/np_ready/_discover.scss | 2 +- .../__snapshots__/field_name.test.tsx.snap | 150 ++++++++++------- .../directives/field_name/field_name.tsx | 32 ++-- .../field_chooser/_field_chooser.scss | 1 - .../np_ready/components/table/table_row.tsx | 7 +- .../__snapshots__/field_icon.test.tsx.snap | 156 ++++++++++++++++-- .../public/field_icon/field_icon.test.tsx | 36 +++- .../public/field_icon/field_icon.tsx | 63 ++++--- .../components/field_manager/field_editor.tsx | 16 +- .../components/field_manager/field_icon.tsx | 37 ----- .../components/field_manager/field_picker.tsx | 2 +- .../lens_field_icon.test.tsx.snap | 10 +- .../indexpattern_datasource/_datapanel.scss | 13 ++ .../indexpattern_datasource/_field_item.scss | 9 +- .../indexpattern_datasource/datapanel.tsx | 5 +- .../dimension_panel/field_select.tsx | 1 + .../field_icon.test.tsx | 55 ------ .../indexpattern_datasource/field_icon.tsx | 43 ----- .../indexpattern_datasource/field_item.tsx | 15 +- .../lens_field_icon.test.tsx | 13 +- .../lens_field_icon.tsx | 18 +- .../add_tooltip_field_popover.test.js.snap | 30 ++-- .../components/add_tooltip_field_popover.js | 13 +- .../public/components/single_field_select.js | 15 +- .../styles/vector/components/field_select.js | 15 +- 25 files changed, 422 insertions(+), 335 deletions(-) delete mode 100644 x-pack/legacy/plugins/graph/public/components/field_manager/field_icon.tsx delete mode 100644 x-pack/legacy/plugins/lens/public/indexpattern_datasource/field_icon.test.tsx delete mode 100644 x-pack/legacy/plugins/lens/public/indexpattern_datasource/field_icon.tsx diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/_discover.scss b/src/legacy/core_plugins/kibana/public/discover/np_ready/_discover.scss index 0da28e41579ae..62e7a96ed80cf 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/_discover.scss +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/_discover.scss @@ -206,7 +206,7 @@ discover-app { background-color: transparent; } -.dscField--noResults { +.dscFieldName--noResults { color: $euiColorDarkShade; } diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/__snapshots__/field_name.test.tsx.snap b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/__snapshots__/field_name.test.tsx.snap index bdb003771619c..23288fc5feb59 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/__snapshots__/field_name.test.tsx.snap +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/__snapshots__/field_name.test.tsx.snap @@ -1,73 +1,109 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`FieldName renders a geo field, useShortDots is set to true 1`] = ` - - - - t.t.test - - + + + +
+
+ + t.t.test + +
+
`; exports[`FieldName renders a number field by providing a field record, useShortDots is set to false 1`] = ` - - - + + + + +
- test.test.test - - + + test.test.test + +
+ `; exports[`FieldName renders a string field by providing fieldType and fieldName 1`] = ` - - - + + + + +
- test - - + + test + +
+ `; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx index 95720bee38df8..54e1c1706a856 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx @@ -18,7 +18,9 @@ */ import React from 'react'; import classNames from 'classnames'; -import { FieldIcon } from '../../../../../../../../../plugins/kibana_react/public'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +import { FieldIcon, FieldIconProps } from '../../../../../../../../../plugins/kibana_react/public'; import { shortenDottedString } from '../../../../../../../../../plugins/data/common/utils'; import { getFieldTypeName } from './field_type_name'; @@ -35,25 +37,35 @@ interface Props { fieldName?: string; fieldType?: string; useShortDots?: boolean; + fieldIconProps?: Omit; } -export function FieldName({ field, fieldName, fieldType, useShortDots }: Props) { +export function FieldName({ field, fieldName, fieldType, useShortDots, fieldIconProps }: Props) { const type = field ? String(field.type) : String(fieldType); const typeName = getFieldTypeName(type); const name = field ? String(field.name) : String(fieldName); const displayName = useShortDots ? shortenDottedString(name) : name; - const className = classNames({ - 'dscField--noResults': field ? !field.rowCount && !field.scripted : false, - // this is currently not styled, should display an icon - scripted: field ? field.scripted : false, + const noResults = field ? !field.rowCount && !field.scripted : false; + + const className = classNames('dscFieldName', { + 'dscFieldName--noResults': noResults, }); return ( - - - {displayName} - + + + + + + {displayName} + + ); } diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/_field_chooser.scss b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/_field_chooser.scss index fe13ac2fafa01..b05775c4ee95c 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/_field_chooser.scss +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/_field_chooser.scss @@ -10,7 +10,6 @@ .dscFieldName { color: $euiColorDarkShade; - padding-left: $euiSizeS; } diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/table/table_row.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/table/table_row.tsx index 7a78e89416361..5b13f6b3655c3 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/table/table_row.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/table/table_row.tsx @@ -87,7 +87,12 @@ export function DocViewTableRow({ )} - + {isCollapsible && ( diff --git a/src/plugins/kibana_react/public/field_icon/__snapshots__/field_icon.test.tsx.snap b/src/plugins/kibana_react/public/field_icon/__snapshots__/field_icon.test.tsx.snap index 870dbdc533267..cde6a625ac8e8 100644 --- a/src/plugins/kibana_react/public/field_icon/__snapshots__/field_icon.test.tsx.snap +++ b/src/plugins/kibana_react/public/field_icon/__snapshots__/field_icon.test.tsx.snap @@ -1,37 +1,159 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FieldIcon renders a blackwhite icon for a string 1`] = ` - `; -exports[`FieldIcon renders a colored icon for a number 1`] = ` - `; -exports[`FieldIcon renders an icon for an unknown type 1`] = ` - +`; + +exports[`FieldIcon renders known field types boolean is rendered 1`] = ` + +`; + +exports[`FieldIcon renders known field types conflict is rendered 1`] = ` + +`; + +exports[`FieldIcon renders known field types date is rendered 1`] = ` + +`; + +exports[`FieldIcon renders known field types geo_point is rendered 1`] = ` + +`; + +exports[`FieldIcon renders known field types geo_shape is rendered 1`] = ` + +`; + +exports[`FieldIcon renders known field types ip is rendered 1`] = ` + +`; + +exports[`FieldIcon renders known field types murmur3 is rendered 1`] = ` + +`; + +exports[`FieldIcon renders known field types nested is rendered 1`] = ` + +`; + +exports[`FieldIcon renders known field types number is rendered 1`] = ` + +`; + +exports[`FieldIcon renders known field types string is rendered 1`] = ` + `; exports[`FieldIcon renders with className if provided 1`] = ` - +`; + +exports[`FieldIcon supports same props as EuiToken 1`] = ` + `; diff --git a/src/plugins/kibana_react/public/field_icon/field_icon.test.tsx b/src/plugins/kibana_react/public/field_icon/field_icon.test.tsx index 90a858e31b4f3..51ff5f603ea37 100644 --- a/src/plugins/kibana_react/public/field_icon/field_icon.test.tsx +++ b/src/plugins/kibana_react/public/field_icon/field_icon.test.tsx @@ -18,24 +18,44 @@ */ import React from 'react'; import { shallow } from 'enzyme'; -import { FieldIcon } from './field_icon'; +import { FieldIcon, typeToEuiIconMap } from './field_icon'; -test('FieldIcon renders a blackwhite icon for a string', () => { - const component = shallow(); +const availableTypes = Object.keys(typeToEuiIconMap); + +describe('FieldIcon renders known field types', () => { + availableTypes.forEach(type => { + test(`${type} is rendered`, () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); + }); +}); + +test('FieldIcon renders an icon for an unknown type', () => { + const component = shallow(); expect(component).toMatchSnapshot(); }); -test('FieldIcon renders a colored icon for a number', () => { - const component = shallow(); +test('FieldIcon supports same props as EuiToken', () => { + const component = shallow( + + ); expect(component).toMatchSnapshot(); }); -test('FieldIcon renders an icon for an unknown type', () => { - const component = shallow(); +test('FieldIcon changes fill when scripted is true', () => { + const component = shallow(); expect(component).toMatchSnapshot(); }); test('FieldIcon renders with className if provided', () => { - const component = shallow(); + const component = shallow(); expect(component).toMatchSnapshot(); }); diff --git a/src/plugins/kibana_react/public/field_icon/field_icon.tsx b/src/plugins/kibana_react/public/field_icon/field_icon.tsx index 2e199a7471a64..2da1eba31e254 100644 --- a/src/plugins/kibana_react/public/field_icon/field_icon.tsx +++ b/src/plugins/kibana_react/public/field_icon/field_icon.tsx @@ -17,14 +17,10 @@ * under the License. */ import React from 'react'; -import { euiPaletteColorBlind, EuiIcon } from '@elastic/eui'; -import { IconSize } from '@elastic/eui/src/components/icon/icon'; +import classNames from 'classnames'; +import { EuiToken, EuiTokenProps } from '@elastic/eui'; -interface IconMapEntry { - icon: string; - color: string; -} -interface FieldIconProps { +export interface FieldIconProps extends Omit { type: | 'boolean' | 'conflict' @@ -39,51 +35,50 @@ interface FieldIconProps { | string | 'nested'; label?: string; - size?: IconSize; - useColor?: boolean; - className?: string; + scripted?: boolean; } -const colors = euiPaletteColorBlind(); - // defaultIcon => a unknown datatype -const defaultIcon = { icon: 'questionInCircle', color: colors[0] }; +const defaultIcon = { iconType: 'questionInCircle', color: 'gray' }; -export const typeToEuiIconMap: Partial> = { - boolean: { icon: 'invert', color: colors[5] }, +export const typeToEuiIconMap: Partial> = { + boolean: { iconType: 'tokenBoolean' }, // icon for an index pattern mapping conflict in discover - conflict: { icon: 'alert', color: colors[8] }, - date: { icon: 'calendar', color: colors[7] }, - geo_point: { icon: 'globe', color: colors[2] }, - geo_shape: { icon: 'globe', color: colors[2] }, - ip: { icon: 'storage', color: colors[8] }, + conflict: { iconType: 'alert', color: 'euiVisColor9' }, + date: { iconType: 'tokenDate' }, + geo_point: { iconType: 'tokenGeo' }, + geo_shape: { iconType: 'tokenGeo' }, + ip: { iconType: 'tokenIP' }, // is a plugin's data type https://www.elastic.co/guide/en/elasticsearch/plugins/current/mapper-murmur3-usage.html - murmur3: { icon: 'document', color: colors[1] }, - number: { icon: 'number', color: colors[0] }, - _source: { icon: 'editorCodeBlock', color: colors[3] }, - string: { icon: 'string', color: colors[4] }, - nested: { icon: 'nested', color: colors[2] }, + murmur3: { iconType: 'tokenFile' }, + number: { iconType: 'tokenNumber' }, + _source: { iconType: 'editorCodeBlock', color: 'gray' }, + string: { iconType: 'tokenString' }, + nested: { iconType: 'tokenNested' }, }; /** - * Field icon used across the app + * Field token icon used across the app */ export function FieldIcon({ type, label, size = 's', - useColor = false, - className = undefined, + scripted, + className, + ...rest }: FieldIconProps) { - const euiIcon = typeToEuiIconMap[type] || defaultIcon; + const token = typeToEuiIconMap[type] || defaultIcon; return ( - ); } diff --git a/x-pack/legacy/plugins/graph/public/components/field_manager/field_editor.tsx b/x-pack/legacy/plugins/graph/public/components/field_manager/field_editor.tsx index 6152f33350917..f2a4c28afcdae 100644 --- a/x-pack/legacy/plugins/graph/public/components/field_manager/field_editor.tsx +++ b/x-pack/legacy/plugins/graph/public/components/field_manager/field_editor.tsx @@ -237,10 +237,18 @@ export function FieldEditor({ renderOption={(option, searchValue, contentClassName) => { const { type, label } = option; return ( - - {' '} - {label} - + + + + + + {label} + + ); }} compressed diff --git a/x-pack/legacy/plugins/graph/public/components/field_manager/field_icon.tsx b/x-pack/legacy/plugins/graph/public/components/field_manager/field_icon.tsx deleted file mode 100644 index 0c099135f631d..0000000000000 --- a/x-pack/legacy/plugins/graph/public/components/field_manager/field_icon.tsx +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { ICON_TYPES, euiPaletteColorBlind, EuiIcon } from '@elastic/eui'; - -function stringToNum(s: string) { - return Array.from(s).reduce((acc, ch) => acc + ch.charCodeAt(0), 1); -} - -function getIconForDataType(dataType: string) { - const icons: Partial>> = { - boolean: 'invert', - date: 'calendar', - geo_point: 'globe', - ip: 'storage', - }; - return icons[dataType] || ICON_TYPES.find(t => t === dataType) || 'document'; -} - -export function getColorForDataType(type: string) { - const iconType = getIconForDataType(type); - const colors = euiPaletteColorBlind(); - const colorIndex = stringToNum(iconType) % colors.length; - return colors[colorIndex]; -} - -export type UnwrapArray = T extends Array ? P : T; - -export function FieldIcon({ type }: { type: string }) { - const iconType = getIconForDataType(type); - - return ; -} diff --git a/x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx b/x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx index b38e3f8430980..30f1fcffd4f67 100644 --- a/x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx +++ b/x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx @@ -122,7 +122,7 @@ function toOptions( .filter(field => isExplorable(field) || field.selected) .map(field => ({ label: field.name, - prepend: , + prepend: , checked: field.selected ? 'on' : undefined, })) ); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/__snapshots__/lens_field_icon.test.tsx.snap b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/__snapshots__/lens_field_icon.test.tsx.snap index 5593a1af00d70..8bbe49b2e0d7f 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/__snapshots__/lens_field_icon.test.tsx.snap +++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/__snapshots__/lens_field_icon.test.tsx.snap @@ -1,10 +1,16 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`LensFieldIcon accepts FieldIcon props 1`] = ` + +`; + exports[`LensFieldIcon renders properly 1`] = ` `; diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/_datapanel.scss b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/_datapanel.scss index ed39beeb7d088..77d4b41a0413c 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/_datapanel.scss +++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/_datapanel.scss @@ -52,3 +52,16 @@ @include euiFormControlLayoutPadding(1, 'right'); @include euiFormControlLayoutPadding(1, 'left'); } + +.lnsInnerIndexPatternDataPanel__filterType { + padding: $euiSizeS; +} + +.lnsInnerIndexPatternDataPanel__filterTypeInner { + display: flex; + align-items: center; + + .lnsFieldListPanel__fieldIcon { + margin-right: $euiSizeS; + } +} diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/_field_item.scss b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/_field_item.scss index 54f9a3787466d..89f6bbf908419 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/_field_item.scss +++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/_field_item.scss @@ -14,7 +14,7 @@ } .lnsFieldItem--missing { - background: lightOrDarkTheme(transparentize($euiColorMediumShade, .9), $euiColorEmptyShade); + background: lightOrDarkTheme(transparentize($euiColorMediumShade, 0.9), $euiColorEmptyShade); color: $euiColorDarkShade; } @@ -24,10 +24,10 @@ display: flex; align-items: flex-start; transition: box-shadow $euiAnimSpeedFast $euiAnimSlightResistance, - background-color $euiAnimSpeedFast $euiAnimSlightResistance; // sass-lint:disable-line indentation + background-color $euiAnimSpeedFast $euiAnimSlightResistance; // sass-lint:disable-line indentation .lnsFieldItem__name { - margin-left: $euiSizeXS; + margin-left: $euiSizeS; flex-grow: 1; } @@ -37,7 +37,8 @@ } .lnsFieldListPanel__fieldIcon { - margin-top: 2px; + margin-top: $euiSizeXS / 2; + margin-right: $euiSizeXS / 2; } .lnsFieldItem__infoIcon { diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 3231ab7d7ff12..69982aed78b40 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -384,6 +384,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ data-test-subj="lnsIndexPatternTypeFilterOptions" items={(availableFieldTypes as DataType[]).map(type => ( - {fieldTypeNames[type]} + + {fieldTypeNames[type]} + ))} /> diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx index 46d7233ba9587..77435fcdf3eed 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/field_select.tsx @@ -169,6 +169,7 @@ export function FieldSelect({ diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/field_icon.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/field_icon.test.tsx deleted file mode 100644 index 6b12bb5feef1b..0000000000000 --- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/field_icon.test.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -/* - * 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 { FieldIcon } from './field_icon'; - -describe('FieldIcon', () => { - it('should render icons', () => { - expect(shallow()).toMatchInlineSnapshot(` - - `); - expect(shallow()).toMatchInlineSnapshot(` - - `); - expect(shallow()).toMatchInlineSnapshot(` - - `); - expect(shallow()).toMatchInlineSnapshot(` - - `); - expect(shallow()).toMatchInlineSnapshot(` - - `); - }); -}); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/field_icon.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/field_icon.tsx deleted file mode 100644 index 796f200bffd97..0000000000000 --- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/field_icon.tsx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { ICON_TYPES, euiPaletteColorBlind, EuiIcon } from '@elastic/eui'; -import classNames from 'classnames'; -import { DataType } from '../types'; - -function stringToNum(s: string) { - return Array.from(s).reduce((acc, ch) => acc + ch.charCodeAt(0), 1); -} - -function getIconForDataType(dataType: string) { - const icons: Partial>> = { - boolean: 'invert', - date: 'calendar', - ip: 'ip', - }; - return icons[dataType] || ICON_TYPES.find(t => t === dataType) || 'empty'; -} - -export function getColorForDataType(type: string) { - const iconType = getIconForDataType(type); - const colors = euiPaletteColorBlind(); - const colorIndex = stringToNum(iconType) % colors.length; - return colors[colorIndex]; -} - -export type UnwrapArray = T extends Array ? P : T; - -export function FieldIcon({ type }: { type: DataType }) { - const iconType = getIconForDataType(type); - - const classes = classNames( - 'lnsFieldListPanel__fieldIcon', - `lnsFieldListPanel__fieldIcon--${type}` - ); - - return ; -} diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/field_item.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/field_item.tsx index 0271d2ca021c5..94d644e6590e1 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/field_item.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/field_item.tsx @@ -46,7 +46,7 @@ import { DragDrop } from '../drag_drop'; import { DatasourceDataPanelProps, DataType } from '../types'; import { BucketedAggregation, FieldStatsResponse } from '../../../../../plugins/lens/common'; import { IndexPattern, IndexPatternField } from './types'; -import { getColorForDataType, LensFieldIcon } from './lens_field_icon'; +import { LensFieldIcon } from './lens_field_icon'; import { trackUiEvent } from '../lens_ui_telemetry'; export interface FieldItemProps { @@ -294,11 +294,6 @@ function FieldItemPopoverContents(props: State & FieldItemProps) { ); } - const euiButtonColor = - field.type === 'string' ? 'accent' : field.type === 'number' ? 'secondary' : 'primary'; - const euiTextColor = - field.type === 'string' ? 'accent' : field.type === 'number' ? 'secondary' : 'default'; - const fromDate = DateMath.parse(dateRange.fromDate); const toDate = DateMath.parse(dateRange.toDate); @@ -391,8 +386,6 @@ function FieldItemPopoverContents(props: State & FieldItemProps) { const specId = i18n.translate('xpack.lens.indexPattern.fieldStatsCountLabel', { defaultMessage: 'Count', }); - const expectedColor = getColorForDataType(field.type); - const seriesColors = expectedColor ? [expectedColor] : undefined; if (field.type === 'date') { return wrapInPopover( @@ -429,7 +422,6 @@ function FieldItemPopoverContents(props: State & FieldItemProps) { yAccessors={['count']} xScaleType={ScaleType.Time} yScaleType={ScaleType.Linear} - customSeriesColors={seriesColors} timeZone="local" /> @@ -453,7 +445,6 @@ function FieldItemPopoverContents(props: State & FieldItemProps) { yAccessors={['count']} xScaleType={ScaleType.Linear} yScaleType={ScaleType.Linear} - customSeriesColors={seriesColors} /> ); @@ -486,7 +477,7 @@ function FieldItemPopoverContents(props: State & FieldItemProps) { )} - + {Math.round((topValue.count / props.sampledValues!) * 100)}% @@ -497,7 +488,7 @@ function FieldItemPopoverContents(props: State & FieldItemProps) { value={topValue.count / props.sampledValues!} max={1} size="s" - color={euiButtonColor} + color="accent" /> ); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/lens_field_icon.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/lens_field_icon.test.tsx index 961e22380bdca..317ce8f032f94 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/lens_field_icon.test.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/lens_field_icon.test.tsx @@ -11,19 +11,14 @@ */ import React from 'react'; import { shallow } from 'enzyme'; -import { LensFieldIcon, getColorForDataType } from './lens_field_icon'; +import { LensFieldIcon } from './lens_field_icon'; test('LensFieldIcon renders properly', () => { const component = shallow(); expect(component).toMatchSnapshot(); }); -test('LensFieldIcon getColorForDataType for a valid type', () => { - const color = getColorForDataType('date'); - expect(color).toEqual('#DA8B45'); -}); - -test('LensFieldIcon getColorForDataType for an invalid type', () => { - const color = getColorForDataType('invalid'); - expect(color).toEqual('#54B399'); +test('LensFieldIcon accepts FieldIcon props', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); }); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/lens_field_icon.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/lens_field_icon.tsx index 2e6a5fcd8115f..06eda73748cef 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/lens_field_icon.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/lens_field_icon.tsx @@ -5,26 +5,16 @@ */ import React from 'react'; -import { euiPaletteColorBlind } from '@elastic/eui'; -import { FieldIcon, typeToEuiIconMap } from '../../../../../../src/plugins/kibana_react/public'; +import { FieldIcon, FieldIconProps } from '../../../../../../src/plugins/kibana_react/public'; import { DataType } from '../types'; import { normalizeOperationDataType } from './utils'; -export function getColorForDataType(type: string) { - const iconMap = typeToEuiIconMap[normalizeOperationDataType(type as DataType)]; - if (iconMap) { - return iconMap.color; - } - return euiPaletteColorBlind()[0]; -} - -export function LensFieldIcon({ type }: { type: DataType }) { +export function LensFieldIcon({ type, ...rest }: FieldIconProps & { type: DataType }) { return ( ); } diff --git a/x-pack/legacy/plugins/maps/public/components/__snapshots__/add_tooltip_field_popover.test.js.snap b/x-pack/legacy/plugins/maps/public/components/__snapshots__/add_tooltip_field_popover.test.js.snap index f37dfdd879c5b..d0cdbe7243abe 100644 --- a/x-pack/legacy/plugins/maps/public/components/__snapshots__/add_tooltip_field_popover.test.js.snap +++ b/x-pack/legacy/plugins/maps/public/components/__snapshots__/add_tooltip_field_popover.test.js.snap @@ -23,7 +23,7 @@ exports[`Should remove selected fields from selectable 1`] = ` id="addTooltipFieldPopover" isOpen={false} ownFocus={true} - panelPaddingSize="m" + panelPaddingSize="none" > , "value": "@timestamp", }, ] } + searchProps={ + Object { + "compressed": true, + } + } searchable={true} singleSelection={false} > @@ -88,7 +93,7 @@ exports[`Should render 1`] = ` id="addTooltipFieldPopover" isOpen={false} ownFocus={true} - panelPaddingSize="m" + panelPaddingSize="none" > , "value": "@timestamp", }, Object { "label": "custom label for prop1", "prepend": , "value": "prop1", }, Object { "label": "prop2", "prepend": , "value": "prop2", }, ] } + searchProps={ + Object { + "compressed": true, + } + } searchable={true} singleSelection={false} > diff --git a/x-pack/legacy/plugins/maps/public/components/add_tooltip_field_popover.js b/x-pack/legacy/plugins/maps/public/components/add_tooltip_field_popover.js index bddb74596f4ef..07bc54663c1d8 100644 --- a/x-pack/legacy/plugins/maps/public/components/add_tooltip_field_popover.js +++ b/x-pack/legacy/plugins/maps/public/components/add_tooltip_field_popover.js @@ -39,7 +39,10 @@ function getOptions(fields, selectedFields) { .map(field => { return { value: field.name, - prepend: 'type' in field ? : null, + prepend: + 'type' in field ? ( + + ) : null, label: 'label' in field ? field.label : field.name, }; }) @@ -127,7 +130,12 @@ export class AddTooltipFieldPopover extends Component { return ( - + {(list, search) => (
{search} @@ -161,6 +169,7 @@ export class AddTooltipFieldPopover extends Component { button={this._renderAddButton()} isOpen={this.state.isPopoverOpen} closePopover={this._closePopover} + panelPaddingSize="none" ownFocus > {this._renderContent()} diff --git a/x-pack/legacy/plugins/maps/public/components/single_field_select.js b/x-pack/legacy/plugins/maps/public/components/single_field_select.js index 7351ce7691a82..98e33454b041b 100644 --- a/x-pack/legacy/plugins/maps/public/components/single_field_select.js +++ b/x-pack/legacy/plugins/maps/public/components/single_field_select.js @@ -8,7 +8,7 @@ import _ from 'lodash'; import PropTypes from 'prop-types'; import React from 'react'; -import { EuiComboBox, EuiHighlight } from '@elastic/eui'; +import { EuiComboBox, EuiHighlight, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { FieldIcon } from '../../../../../../src/plugins/kibana_react/public'; function fieldsToOptions(fields) { @@ -30,11 +30,14 @@ function fieldsToOptions(fields) { function renderOption(option, searchValue, contentClassName) { return ( - - -   - {option.label} - + + + + + + {option.label} + + ); } diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/field_select.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/field_select.js index a32c2ce04d735..cf0ec5589d6bc 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/field_select.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/field_select.js @@ -7,18 +7,21 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { EuiComboBox, EuiHighlight } from '@elastic/eui'; +import { EuiComboBox, EuiHighlight, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { FIELD_ORIGIN } from '../../../../../common/constants'; import { i18n } from '@kbn/i18n'; import { FieldIcon } from '../../../../../../../../../src/plugins/kibana_react/public'; function renderOption(option, searchValue, contentClassName) { return ( - - -   - {option.label} - + + + + + + {option.label} + + ); } From 9c8c47befb177ba9fd5e4a102ae363140e2668a7 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Fri, 21 Feb 2020 16:37:39 -0700 Subject: [PATCH 016/123] [File upload] Update remaining File Upload dependencies for NP migration (#58128) * Remove old route ref, no longer used * Use core elasticsearch service * Remove getSavedObjectsRepository, use NP internalRepository * Update tests and clean up * Remove unused test vars --- x-pack/legacy/plugins/file_upload/index.js | 22 ++++------- .../call_with_internal_user_factory.d.ts | 7 ---- .../client/call_with_internal_user_factory.js | 18 --------- .../call_with_internal_user_factory.test.ts | 22 ----------- .../client/call_with_request_factory.js | 15 ++++--- .../server/kibana_server_services.js | 18 +++++++++ .../plugins/file_upload/server/plugin.js | 22 ++++++----- .../file_upload/server/routes/file_upload.js | 10 ++--- .../telemetry/file_upload_usage_collector.ts | 12 +----- .../server/telemetry/telemetry.test.ts | 10 +---- .../file_upload/server/telemetry/telemetry.ts | 39 ++++--------------- 11 files changed, 63 insertions(+), 132 deletions(-) delete mode 100644 x-pack/legacy/plugins/file_upload/server/client/call_with_internal_user_factory.d.ts delete mode 100644 x-pack/legacy/plugins/file_upload/server/client/call_with_internal_user_factory.js delete mode 100644 x-pack/legacy/plugins/file_upload/server/client/call_with_internal_user_factory.test.ts create mode 100644 x-pack/legacy/plugins/file_upload/server/kibana_server_services.js diff --git a/x-pack/legacy/plugins/file_upload/index.js b/x-pack/legacy/plugins/file_upload/index.js index d29226c802b06..23e1e1d98aa7f 100644 --- a/x-pack/legacy/plugins/file_upload/index.js +++ b/x-pack/legacy/plugins/file_upload/index.js @@ -8,9 +8,10 @@ import { mappings } from './mappings'; export const fileUpload = kibana => { return new kibana.Plugin({ - require: ['elasticsearch', 'xpack_main'], + require: ['elasticsearch'], name: 'file_upload', id: 'file_upload', + // TODO: uiExports and savedObjectSchemas to be removed on migration uiExports: { mappings, }, @@ -22,23 +23,14 @@ export const fileUpload = kibana => { init(server) { const coreSetup = server.newPlatform.setup.core; + const coreStart = server.newPlatform.start.core; const { usageCollection } = server.newPlatform.setup.plugins; - const pluginsSetup = { + const pluginsStart = { usageCollection, }; - - // legacy dependencies - const __LEGACY = { - route: server.route.bind(server), - plugins: { - elasticsearch: server.plugins.elasticsearch, - }, - savedObjects: { - getSavedObjectsRepository: server.savedObjects.getSavedObjectsRepository, - }, - }; - - new FileUploadPlugin().setup(coreSetup, pluginsSetup, __LEGACY); + const fileUploadPlugin = new FileUploadPlugin(); + fileUploadPlugin.setup(coreSetup); + fileUploadPlugin.start(coreStart, pluginsStart); }, }); }; diff --git a/x-pack/legacy/plugins/file_upload/server/client/call_with_internal_user_factory.d.ts b/x-pack/legacy/plugins/file_upload/server/client/call_with_internal_user_factory.d.ts deleted file mode 100644 index 9c1000db8cb56..0000000000000 --- a/x-pack/legacy/plugins/file_upload/server/client/call_with_internal_user_factory.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export function callWithInternalUserFactory(elasticsearchPlugin: any): any; diff --git a/x-pack/legacy/plugins/file_upload/server/client/call_with_internal_user_factory.js b/x-pack/legacy/plugins/file_upload/server/client/call_with_internal_user_factory.js deleted file mode 100644 index 2e5431bdd6ce2..0000000000000 --- a/x-pack/legacy/plugins/file_upload/server/client/call_with_internal_user_factory.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { once } from 'lodash'; - -const _callWithInternalUser = once(elasticsearchPlugin => { - const { callWithInternalUser } = elasticsearchPlugin.getCluster('admin'); - return callWithInternalUser; -}); - -export const callWithInternalUserFactory = elasticsearchPlugin => { - return (...args) => { - return _callWithInternalUser(elasticsearchPlugin)(...args); - }; -}; diff --git a/x-pack/legacy/plugins/file_upload/server/client/call_with_internal_user_factory.test.ts b/x-pack/legacy/plugins/file_upload/server/client/call_with_internal_user_factory.test.ts deleted file mode 100644 index 04c5013ed8e67..0000000000000 --- a/x-pack/legacy/plugins/file_upload/server/client/call_with_internal_user_factory.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { callWithInternalUserFactory } from './call_with_internal_user_factory'; - -describe('call_with_internal_user_factory', () => { - describe('callWithInternalUserFactory', () => { - it('should use internal user "admin"', () => { - const callWithInternalUser: any = jest.fn(); - const elasticsearchPlugin: any = { - getCluster: jest.fn(() => ({ callWithInternalUser })), - }; - const callWithInternalUserInstance = callWithInternalUserFactory(elasticsearchPlugin); - callWithInternalUserInstance(); - - expect(elasticsearchPlugin.getCluster).toHaveBeenCalledWith('admin'); - }); - }); -}); diff --git a/x-pack/legacy/plugins/file_upload/server/client/call_with_request_factory.js b/x-pack/legacy/plugins/file_upload/server/client/call_with_request_factory.js index a0b0d2d1c7ce3..bef6c369fd9ac 100644 --- a/x-pack/legacy/plugins/file_upload/server/client/call_with_request_factory.js +++ b/x-pack/legacy/plugins/file_upload/server/client/call_with_request_factory.js @@ -5,14 +5,17 @@ */ import { once } from 'lodash'; +import { getDataClient } from '../kibana_server_services'; -const callWithRequest = once(elasticsearchPlugin => { - const cluster = elasticsearchPlugin.getCluster('data'); - return cluster.callWithRequest; -}); +const callWithRequest = once(() => getDataClient()); -export const callWithRequestFactory = (elasticsearchPlugin, request) => { +export const callWithRequestFactory = request => { return (...args) => { - return callWithRequest(elasticsearchPlugin)(request, ...args); + return ( + callWithRequest() + .asScoped(request) + // @ts-ignore + .callAsCurrentUser(...args) + ); }; }; diff --git a/x-pack/legacy/plugins/file_upload/server/kibana_server_services.js b/x-pack/legacy/plugins/file_upload/server/kibana_server_services.js new file mode 100644 index 0000000000000..104e49015ba80 --- /dev/null +++ b/x-pack/legacy/plugins/file_upload/server/kibana_server_services.js @@ -0,0 +1,18 @@ +/* + * 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. + */ + +let dataClient; + +export const setElasticsearchClientServices = elasticsearch => { + ({ dataClient } = elasticsearch); +}; +export const getDataClient = () => dataClient; + +let internalRepository; +export const setInternalRepository = createInternalRepository => { + internalRepository = createInternalRepository(); +}; +export const getInternalRepository = () => internalRepository; diff --git a/x-pack/legacy/plugins/file_upload/server/plugin.js b/x-pack/legacy/plugins/file_upload/server/plugin.js index 23fb8bda897f0..c448676f813ea 100644 --- a/x-pack/legacy/plugins/file_upload/server/plugin.js +++ b/x-pack/legacy/plugins/file_upload/server/plugin.js @@ -5,19 +5,23 @@ */ import { initRoutes } from './routes/file_upload'; +import { setElasticsearchClientServices, setInternalRepository } from './kibana_server_services'; import { registerFileUploadUsageCollector } from './telemetry'; export class FileUploadPlugin { - setup(core, plugins, __LEGACY) { - const elasticsearchPlugin = __LEGACY.plugins.elasticsearch; - const getSavedObjectsRepository = __LEGACY.savedObjects.getSavedObjectsRepository; - const router = core.http.createRouter(); + constructor() { + this.router = null; + } + + setup(core) { + setElasticsearchClientServices(core.elasticsearch); + this.router = core.http.createRouter(); + } - initRoutes(router, elasticsearchPlugin, getSavedObjectsRepository); + start(core, plugins) { + initRoutes(this.router, core.savedObjects.getSavedObjectsRepository); + setInternalRepository(core.savedObjects.createInternalRepository); - registerFileUploadUsageCollector(plugins.usageCollection, { - elasticsearchPlugin, - getSavedObjectsRepository, - }); + registerFileUploadUsageCollector(plugins.usageCollection); } } diff --git a/x-pack/legacy/plugins/file_upload/server/routes/file_upload.js b/x-pack/legacy/plugins/file_upload/server/routes/file_upload.js index 1c27c2d7d68e9..acbc907729d95 100644 --- a/x-pack/legacy/plugins/file_upload/server/routes/file_upload.js +++ b/x-pack/legacy/plugins/file_upload/server/routes/file_upload.js @@ -75,7 +75,7 @@ export const idConditionalValidation = (body, boolHasId) => ) .validate(body); -const finishValidationAndProcessReq = (elasticsearchPlugin, getSavedObjectsRepository) => { +const finishValidationAndProcessReq = () => { return async (con, req, { ok, badRequest }) => { const { query: { id }, @@ -86,7 +86,7 @@ const finishValidationAndProcessReq = (elasticsearchPlugin, getSavedObjectsRepos let resp; try { const validIdReqData = idConditionalValidation(body, boolHasId); - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, req); + const callWithRequest = callWithRequestFactory(req); const { importData: importDataFunc } = importDataProvider(callWithRequest); const { index, settings, mappings, ingestPipeline, data } = validIdReqData; @@ -103,7 +103,7 @@ const finishValidationAndProcessReq = (elasticsearchPlugin, getSavedObjectsRepos resp = ok({ body: processedReq }); // If no id's been established then this is a new index, update telemetry if (!boolHasId) { - await updateTelemetry({ elasticsearchPlugin, getSavedObjectsRepository }); + await updateTelemetry(); } } else { resp = badRequest(`Error processing request 1: ${processedReq.error.message}`, ['body']); @@ -115,7 +115,7 @@ const finishValidationAndProcessReq = (elasticsearchPlugin, getSavedObjectsRepos }; }; -export const initRoutes = (router, esPlugin, getSavedObjectsRepository) => { +export const initRoutes = router => { router.post( { path: `${IMPORT_ROUTE}{id?}`, @@ -125,6 +125,6 @@ export const initRoutes = (router, esPlugin, getSavedObjectsRepository) => { }, options, }, - finishValidationAndProcessReq(esPlugin, getSavedObjectsRepository) + finishValidationAndProcessReq() ); }; diff --git a/x-pack/legacy/plugins/file_upload/server/telemetry/file_upload_usage_collector.ts b/x-pack/legacy/plugins/file_upload/server/telemetry/file_upload_usage_collector.ts index a2b359ae11638..2c2b1183fd5bf 100644 --- a/x-pack/legacy/plugins/file_upload/server/telemetry/file_upload_usage_collector.ts +++ b/x-pack/legacy/plugins/file_upload/server/telemetry/file_upload_usage_collector.ts @@ -9,19 +9,11 @@ import { getTelemetry, initTelemetry } from './telemetry'; const TELEMETRY_TYPE = 'fileUploadTelemetry'; -export function registerFileUploadUsageCollector( - usageCollection: UsageCollectionSetup, - deps: { - elasticsearchPlugin: any; - getSavedObjectsRepository: any; - } -): void { - const { elasticsearchPlugin, getSavedObjectsRepository } = deps; +export function registerFileUploadUsageCollector(usageCollection: UsageCollectionSetup): void { const fileUploadUsageCollector = usageCollection.makeUsageCollector({ type: TELEMETRY_TYPE, isReady: () => true, - fetch: async () => - (await getTelemetry(elasticsearchPlugin, getSavedObjectsRepository)) || initTelemetry(), + fetch: async () => (await getTelemetry()) || initTelemetry(), }); usageCollection.registerCollector(fileUploadUsageCollector); diff --git a/x-pack/legacy/plugins/file_upload/server/telemetry/telemetry.test.ts b/x-pack/legacy/plugins/file_upload/server/telemetry/telemetry.test.ts index 1c785d8e7b61c..fadad307c0710 100644 --- a/x-pack/legacy/plugins/file_upload/server/telemetry/telemetry.test.ts +++ b/x-pack/legacy/plugins/file_upload/server/telemetry/telemetry.test.ts @@ -6,8 +6,6 @@ import { getTelemetry, updateTelemetry } from './telemetry'; -const elasticsearchPlugin: any = null; -const getSavedObjectsRepository: any = null; const internalRepository = () => ({ get: jest.fn(() => null), create: jest.fn(() => ({ attributes: 'test' })), @@ -25,7 +23,7 @@ describe('file upload plugin telemetry', () => { describe('getTelemetry', () => { it('should get existing telemetry', async () => { const internalRepo = mockInit(); - await getTelemetry(elasticsearchPlugin, getSavedObjectsRepository, internalRepo); + await getTelemetry(internalRepo); expect(internalRepo.update.mock.calls.length).toBe(0); expect(internalRepo.get.mock.calls.length).toBe(1); expect(internalRepo.create.mock.calls.length).toBe(0); @@ -40,11 +38,7 @@ describe('file upload plugin telemetry', () => { }, }); - await updateTelemetry({ - elasticsearchPlugin, - getSavedObjectsRepository, - internalRepo, - }); + await updateTelemetry(internalRepo); expect(internalRepo.update.mock.calls.length).toBe(1); expect(internalRepo.get.mock.calls.length).toBe(1); expect(internalRepo.create.mock.calls.length).toBe(0); diff --git a/x-pack/legacy/plugins/file_upload/server/telemetry/telemetry.ts b/x-pack/legacy/plugins/file_upload/server/telemetry/telemetry.ts index 5ffa735f4c83a..2978dec7aa68d 100644 --- a/x-pack/legacy/plugins/file_upload/server/telemetry/telemetry.ts +++ b/x-pack/legacy/plugins/file_upload/server/telemetry/telemetry.ts @@ -5,7 +5,8 @@ */ import _ from 'lodash'; -import { callWithInternalUserFactory } from '../client/call_with_internal_user_factory'; +// @ts-ignore +import { getInternalRepository } from '../kibana_server_services'; export const TELEMETRY_DOC_ID = 'file-upload-telemetry'; @@ -17,27 +18,14 @@ export interface TelemetrySavedObject { attributes: Telemetry; } -export function getInternalRepository( - elasticsearchPlugin: any, - getSavedObjectsRepository: any -): any { - const callWithInternalUser = callWithInternalUserFactory(elasticsearchPlugin); - return getSavedObjectsRepository(callWithInternalUser); -} - export function initTelemetry(): Telemetry { return { filesUploadedTotalCount: 0, }; } -export async function getTelemetry( - elasticsearchPlugin: any, - getSavedObjectsRepository: any, - internalRepo?: object -): Promise { - const internalRepository = - internalRepo || getInternalRepository(elasticsearchPlugin, getSavedObjectsRepository); +export async function getTelemetry(internalRepo?: object): Promise { + const internalRepository = internalRepo || getInternalRepository(); let telemetrySavedObject; try { @@ -49,22 +37,9 @@ export async function getTelemetry( return telemetrySavedObject ? telemetrySavedObject.attributes : null; } -export async function updateTelemetry({ - elasticsearchPlugin, - getSavedObjectsRepository, - internalRepo, -}: { - elasticsearchPlugin: any; - getSavedObjectsRepository: any; - internalRepo?: any; -}) { - const internalRepository = - internalRepo || getInternalRepository(elasticsearchPlugin, getSavedObjectsRepository); - let telemetry = await getTelemetry( - elasticsearchPlugin, - getSavedObjectsRepository, - internalRepository - ); +export async function updateTelemetry(internalRepo?: any) { + const internalRepository = internalRepo || getInternalRepository(); + let telemetry = await getTelemetry(internalRepository); // Create if doesn't exist if (!telemetry || _.isEmpty(telemetry)) { const newTelemetrySavedObject = await internalRepository.create( From 98aa1d2d4f974f72a9a5397b1b91f11509f6fb7a Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Sat, 22 Feb 2020 07:29:44 -0700 Subject: [PATCH 017/123] [SIEM] [Case] Enable case by default. Snake to camel on UI (#57936) --- .../siem/public/components/links/index.tsx | 5 +- .../components/navigation/index.test.tsx | 4 +- .../siem/public/containers/case/api.ts | 21 ++-- .../siem/public/containers/case/types.ts | 40 ++++++-- .../public/containers/case/use_get_case.tsx | 8 +- .../public/containers/case/use_get_cases.tsx | 20 ++-- .../containers/case/use_update_case.tsx | 6 +- .../siem/public/containers/case/utils.ts | 33 +++++++ .../components/all_cases/__mock__/index.tsx | 77 +++++++++++++++ .../case/components/all_cases/columns.tsx | 42 +++++--- .../case/components/all_cases/index.test.tsx | 97 +++++++++++++++++++ .../pages/case/components/all_cases/index.tsx | 34 +++---- .../components/case_view/__mock__/index.tsx | 34 +++++++ .../case/components/case_view/index.test.tsx | 82 ++++++++++++++++ .../pages/case/components/case_view/index.tsx | 35 +++++-- .../pages/case/components/create/index.tsx | 4 +- .../pages/case/components/user_list/index.tsx | 4 +- .../public/pages/home/home_navigations.tsx | 2 +- x-pack/plugins/case/server/config.ts | 4 +- x-pack/plugins/case/server/plugin.ts | 1 + .../routes/api/__tests__/update_case.test.ts | 39 +++++++- .../case/server/routes/api/get_all_cases.ts | 7 +- .../plugins/case/server/routes/api/schema.ts | 5 + .../plugins/case/server/routes/api/types.ts | 13 +++ .../case/server/routes/api/update_case.ts | 71 ++++++++++++-- .../plugins/case/server/routes/api/utils.ts | 18 ++++ 26 files changed, 605 insertions(+), 101 deletions(-) create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/__mock__/index.tsx create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/index.test.tsx create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/case_view/__mock__/index.tsx create mode 100644 x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx diff --git a/x-pack/legacy/plugins/siem/public/components/links/index.tsx b/x-pack/legacy/plugins/siem/public/components/links/index.tsx index 4f74f9ff2f5d6..b6548e3e950ba 100644 --- a/x-pack/legacy/plugins/siem/public/components/links/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/links/index.tsx @@ -44,7 +44,10 @@ const CaseDetailsLinkComponent: React.FC<{ children?: React.ReactNode; detailNam children, detailName, }) => ( - + {children ? children : detailName} ); diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/navigation/index.test.tsx index 8eb08bd3d62f0..e1b3951a2317d 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/navigation/index.test.tsx @@ -67,7 +67,7 @@ describe('SIEM Navigation', () => { detailName: undefined, navTabs: { case: { - disabled: true, + disabled: false, href: '#/link-to/case', id: 'case', name: 'Case', @@ -160,7 +160,7 @@ describe('SIEM Navigation', () => { filters: [], navTabs: { case: { - disabled: true, + disabled: false, href: '#/link-to/case', id: 'case', name: 'Case', diff --git a/x-pack/legacy/plugins/siem/public/containers/case/api.ts b/x-pack/legacy/plugins/siem/public/containers/case/api.ts index 830e00c70975e..bff3bfd62a85c 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/api.ts +++ b/x-pack/legacy/plugins/siem/public/containers/case/api.ts @@ -5,12 +5,12 @@ */ import { KibanaServices } from '../../lib/kibana'; -import { AllCases, FetchCasesProps, Case, NewCase, SortFieldCase } from './types'; -import { Direction } from '../../graphql/types'; +import { FetchCasesProps, Case, NewCase, SortFieldCase, AllCases, CaseSnake } from './types'; import { throwIfNotOk } from '../../hooks/api/api'; import { CASES_URL } from './constants'; +import { convertToCamelCase, convertAllCasesToCamel } from './utils'; -export const getCase = async (caseId: string, includeComments: boolean) => { +export const getCase = async (caseId: string, includeComments: boolean): Promise => { const response = await KibanaServices.get().http.fetch(`${CASES_URL}/${caseId}`, { method: 'GET', asResponse: true, @@ -19,7 +19,7 @@ export const getCase = async (caseId: string, includeComments: boolean) => { }, }); await throwIfNotOk(response.response); - return response.body!; + return convertToCamelCase(response.body!); }; export const getCases = async ({ @@ -31,7 +31,7 @@ export const getCases = async ({ page: 1, perPage: 20, sortField: SortFieldCase.createdAt, - sortOrder: Direction.desc, + sortOrder: 'desc', }, }: FetchCasesProps): Promise => { const tags = [...(filterOptions.tags?.map(t => `case-workflow.attributes.tags: ${t}`) ?? [])]; @@ -46,7 +46,7 @@ export const getCases = async ({ asResponse: true, }); await throwIfNotOk(response.response); - return response.body!; + return convertAllCasesToCamel(response.body!); }; export const createCase = async (newCase: NewCase): Promise => { @@ -56,18 +56,19 @@ export const createCase = async (newCase: NewCase): Promise => { body: JSON.stringify(newCase), }); await throwIfNotOk(response.response); - return response.body!; + return convertToCamelCase(response.body!); }; export const updateCaseProperty = async ( caseId: string, - updatedCase: Partial + updatedCase: Partial, + version: string ): Promise> => { const response = await KibanaServices.get().http.fetch(`${CASES_URL}/${caseId}`, { method: 'PATCH', asResponse: true, - body: JSON.stringify(updatedCase), + body: JSON.stringify({ case: updatedCase, version }), }); await throwIfNotOk(response.response); - return response.body!; + return convertToCamelCase, Partial>(response.body!); }; diff --git a/x-pack/legacy/plugins/siem/public/containers/case/types.ts b/x-pack/legacy/plugins/siem/public/containers/case/types.ts index 0f80b2327a30c..1aea0b0f50a89 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/types.ts +++ b/x-pack/legacy/plugins/siem/public/containers/case/types.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Direction } from '../../graphql/types'; interface FormData { isNew?: boolean; } @@ -15,22 +14,35 @@ export interface NewCase extends FormData { title: string; } -export interface Case { +export interface CaseSnake { case_id: string; created_at: string; - created_by: ElasticUser; + created_by: ElasticUserSnake; description: string; state: string; tags: string[]; title: string; updated_at: string; + version?: string; +} + +export interface Case { + caseId: string; + createdAt: string; + createdBy: ElasticUser; + description: string; + state: string; + tags: string[]; + title: string; + updatedAt: string; + version?: string; } export interface QueryParams { page: number; perPage: number; sortField: SortFieldCase; - sortOrder: Direction; + sortOrder: 'asc' | 'desc'; } export interface FilterOptions { @@ -38,21 +50,33 @@ export interface FilterOptions { tags: string[]; } +export interface AllCasesSnake { + cases: CaseSnake[]; + page: number; + per_page: number; + total: number; +} + export interface AllCases { cases: Case[]; page: number; - per_page: number; + perPage: number; total: number; } export enum SortFieldCase { - createdAt = 'created_at', + createdAt = 'createdAt', state = 'state', - updatedAt = 'updated_at', + updatedAt = 'updatedAt', +} + +export interface ElasticUserSnake { + readonly username: string; + readonly full_name?: string | null; } export interface ElasticUser { readonly username: string; - readonly full_name?: string; + readonly fullName?: string | null; } export interface FetchCasesProps { diff --git a/x-pack/legacy/plugins/siem/public/containers/case/use_get_case.tsx b/x-pack/legacy/plugins/siem/public/containers/case/use_get_case.tsx index 8cc961c68fdf0..bf76b69ef22d6 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/use_get_case.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/case/use_get_case.tsx @@ -50,16 +50,16 @@ const dataFetchReducer = (state: CaseState, action: Action): CaseState => { } }; const initialData: Case = { - case_id: '', - created_at: '', - created_by: { + caseId: '', + createdAt: '', + createdBy: { username: '', }, description: '', state: '', tags: [], title: '', - updated_at: '', + updatedAt: '', }; export const useGetCase = (caseId: string): [CaseState] => { diff --git a/x-pack/legacy/plugins/siem/public/containers/case/use_get_cases.tsx b/x-pack/legacy/plugins/siem/public/containers/case/use_get_cases.tsx index db9c07747ba04..4037823ccfc94 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/use_get_cases.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/case/use_get_cases.tsx @@ -17,7 +17,6 @@ import { } from './constants'; import { AllCases, SortFieldCase, FilterOptions, QueryParams } from './types'; import { getTypedPayload } from './utils'; -import { Direction } from '../../graphql/types'; import { errorToToaster } from '../../components/ml/api/error_to_toaster'; import { useStateToaster } from '../../components/toasters'; import * as i18n from './translations'; @@ -31,16 +30,9 @@ export interface UseGetCasesState { filterOptions: FilterOptions; } -export interface QueryArgs { - page?: number; - perPage?: number; - sortField?: SortFieldCase; - sortOrder?: Direction; -} - export interface Action { type: string; - payload?: AllCases | QueryArgs | FilterOptions; + payload?: AllCases | Partial | FilterOptions; } const dataFetchReducer = (state: UseGetCasesState, action: Action): UseGetCasesState => { switch (action.type) { @@ -83,13 +75,13 @@ const dataFetchReducer = (state: UseGetCasesState, action: Action): UseGetCasesS const initialData: AllCases = { page: 0, - per_page: 0, + perPage: 0, total: 0, cases: [], }; export const useGetCases = (): [ UseGetCasesState, - Dispatch>, + Dispatch>>, Dispatch> ] => { const [state, dispatch] = useReducer(dataFetchReducer, { @@ -104,11 +96,11 @@ export const useGetCases = (): [ page: DEFAULT_TABLE_ACTIVE_PAGE, perPage: DEFAULT_TABLE_LIMIT, sortField: SortFieldCase.createdAt, - sortOrder: Direction.desc, + sortOrder: 'desc', }, }); - const [queryParams, setQueryParams] = useState(state.queryParams as QueryArgs); - const [filterQuery, setFilters] = useState(state.filterOptions as FilterOptions); + const [queryParams, setQueryParams] = useState>(state.queryParams); + const [filterQuery, setFilters] = useState(state.filterOptions); const [, dispatchToaster] = useStateToaster(); useEffect(() => { diff --git a/x-pack/legacy/plugins/siem/public/containers/case/use_update_case.tsx b/x-pack/legacy/plugins/siem/public/containers/case/use_update_case.tsx index 68592c17e58dc..62e3d87b528c0 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/use_update_case.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/case/use_update_case.tsx @@ -96,7 +96,11 @@ export const useUpdateCase = ( const updateData = async (updateKey: keyof Case) => { dispatch({ type: FETCH_INIT }); try { - const response = await updateCaseProperty(caseId, { [updateKey]: state.data[updateKey] }); + const response = await updateCaseProperty( + caseId, + { [updateKey]: state.data[updateKey] }, + state.data.version ?? '' // saved object versions are typed as string | undefined, hope that's not true + ); dispatch({ type: FETCH_SUCCESS, payload: response }); } catch (error) { errorToToaster({ title: i18n.ERROR_TITLE, error, dispatchToaster }); diff --git a/x-pack/legacy/plugins/siem/public/containers/case/utils.ts b/x-pack/legacy/plugins/siem/public/containers/case/utils.ts index 8e6eaca1a8f0c..14a3819bdfdad 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/utils.ts +++ b/x-pack/legacy/plugins/siem/public/containers/case/utils.ts @@ -4,4 +4,37 @@ * you may not use this file except in compliance with the Elastic License. */ +import { camelCase, isArray, isObject, set } from 'lodash'; +import { AllCases, AllCasesSnake, Case, CaseSnake } from './types'; + export const getTypedPayload = (a: unknown): T => a as T; + +export const convertArrayToCamelCase = (arrayOfSnakes: unknown[]): unknown[] => + arrayOfSnakes.reduce((acc: unknown[], value) => { + if (isArray(value)) { + return [...acc, convertArrayToCamelCase(value)]; + } else if (isObject(value)) { + return [...acc, convertToCamelCase(value)]; + } else { + return [...acc, value]; + } + }, []); + +export const convertToCamelCase = (snakeCase: T): U => + Object.entries(snakeCase).reduce((acc, [key, value]) => { + if (isArray(value)) { + set(acc, camelCase(key), convertArrayToCamelCase(value)); + } else if (isObject(value)) { + set(acc, camelCase(key), convertToCamelCase(value)); + } else { + set(acc, camelCase(key), value); + } + return acc; + }, {} as U); + +export const convertAllCasesToCamel = (snakeCases: AllCasesSnake): AllCases => ({ + cases: snakeCases.cases.map(snakeCase => convertToCamelCase(snakeCase)), + page: snakeCases.page, + perPage: snakeCases.per_page, + total: snakeCases.total, +}); diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/__mock__/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/__mock__/index.tsx new file mode 100644 index 0000000000000..98a67304fcf1f --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/__mock__/index.tsx @@ -0,0 +1,77 @@ +/* + * 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 { SortFieldCase } from '../../../../../containers/case/types'; +import { UseGetCasesState } from '../../../../../containers/case/use_get_cases'; + +export const useGetCasesMockState: UseGetCasesState = { + data: { + cases: [ + { + caseId: '3c4ddcc0-4e99-11ea-9290-35d05cb55c15', + createdAt: '2020-02-13T19:44:23.627Z', + createdBy: { username: 'elastic' }, + description: 'Security banana Issue', + state: 'open', + tags: ['defacement'], + title: 'Another horrible breach', + updatedAt: '2020-02-13T19:44:23.627Z', + }, + { + caseId: '362a5c10-4e99-11ea-9290-35d05cb55c15', + createdAt: '2020-02-13T19:44:13.328Z', + createdBy: { username: 'elastic' }, + description: 'Security banana Issue', + state: 'open', + tags: ['phishing'], + title: 'Bad email', + updatedAt: '2020-02-13T19:44:13.328Z', + }, + { + caseId: '34f8b9e0-4e99-11ea-9290-35d05cb55c15', + createdAt: '2020-02-13T19:44:11.328Z', + createdBy: { username: 'elastic' }, + description: 'Security banana Issue', + state: 'open', + tags: ['phishing'], + title: 'Bad email', + updatedAt: '2020-02-13T19:44:11.328Z', + }, + { + caseId: '31890e90-4e99-11ea-9290-35d05cb55c15', + createdAt: '2020-02-13T19:44:05.563Z', + createdBy: { username: 'elastic' }, + description: 'Security banana Issue', + state: 'closed', + tags: ['phishing'], + title: 'Uh oh', + updatedAt: '2020-02-18T21:32:24.056Z', + }, + { + caseId: '2f5b3210-4e99-11ea-9290-35d05cb55c15', + createdAt: '2020-02-13T19:44:01.901Z', + createdBy: { username: 'elastic' }, + description: 'Security banana Issue', + state: 'open', + tags: ['phishing'], + title: 'Uh oh', + updatedAt: '2020-02-13T19:44:01.901Z', + }, + ], + page: 1, + perPage: 5, + total: 10, + }, + isLoading: false, + isError: false, + queryParams: { + page: 1, + perPage: 5, + sortField: SortFieldCase.createdAt, + sortOrder: 'desc', + }, + filterOptions: { search: '', tags: [] }, +}; diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/columns.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/columns.tsx index 92cd16fd2000e..4c47bf605051d 100644 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/columns.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/columns.tsx @@ -14,14 +14,15 @@ import * as i18n from './translations'; export type CasesColumns = EuiTableFieldDataColumnType | EuiTableComputedColumnType; -const renderStringField = (field: string) => (field != null ? field : getEmptyTagValue()); +const renderStringField = (field: string, dataTestSubj: string) => + field != null ? {field} : getEmptyTagValue(); export const getCasesColumns = (): CasesColumns[] => [ { name: i18n.CASE_TITLE, render: (theCase: Case) => { - if (theCase.case_id != null && theCase.title != null) { - return {theCase.title}; + if (theCase.caseId != null && theCase.title != null) { + return {theCase.title}; } return getEmptyTagValue(); }, @@ -34,7 +35,11 @@ export const getCasesColumns = (): CasesColumns[] => [ return ( {tags.map((tag: string, i: number) => ( - + {tag} ))} @@ -46,28 +51,39 @@ export const getCasesColumns = (): CasesColumns[] => [ truncateText: true, }, { - field: 'created_at', + field: 'createdAt', name: i18n.CREATED_AT, sortable: true, - render: (createdAt: Case['created_at']) => { + render: (createdAt: Case['createdAt']) => { if (createdAt != null) { - return ; + return ( + + ); } return getEmptyTagValue(); }, }, { - field: 'created_by.username', + field: 'createdBy.username', name: i18n.REPORTER, - render: (createdBy: Case['created_by']['username']) => renderStringField(createdBy), + render: (createdBy: Case['createdBy']['username']) => + renderStringField(createdBy, `case-table-column-username`), }, { - field: 'updated_at', + field: 'updatedAt', name: i18n.LAST_UPDATED, sortable: true, - render: (updatedAt: Case['updated_at']) => { + render: (updatedAt: Case['updatedAt']) => { if (updatedAt != null) { - return ; + return ( + + ); } return getEmptyTagValue(); }, @@ -76,6 +92,6 @@ export const getCasesColumns = (): CasesColumns[] => [ field: 'state', name: i18n.STATE, sortable: true, - render: (state: Case['state']) => renderStringField(state), + render: (state: Case['state']) => renderStringField(state, `case-table-column-state`), }, ]; diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/index.test.tsx new file mode 100644 index 0000000000000..5a87cf53142f7 --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/index.test.tsx @@ -0,0 +1,97 @@ +/* + * 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 { mount } from 'enzyme'; +import moment from 'moment-timezone'; +import { AllCases } from './'; +import { TestProviders } from '../../../../mock'; +import { useGetCasesMockState } from './__mock__'; +import * as apiHook from '../../../../containers/case/use_get_cases'; + +describe('AllCases', () => { + const setQueryParams = jest.fn(); + const setFilters = jest.fn(); + beforeEach(() => { + jest.resetAllMocks(); + jest + .spyOn(apiHook, 'useGetCases') + .mockReturnValue([useGetCasesMockState, setQueryParams, setFilters]); + moment.tz.setDefault('UTC'); + }); + it('should render AllCases', () => { + const wrapper = mount( + + + + ); + expect( + wrapper + .find(`a[data-test-subj="case-details-link"]`) + .first() + .prop('href') + ).toEqual(`#/link-to/case/${useGetCasesMockState.data.cases[0].caseId}`); + expect( + wrapper + .find(`a[data-test-subj="case-details-link"]`) + .first() + .text() + ).toEqual(useGetCasesMockState.data.cases[0].title); + expect( + wrapper + .find(`[data-test-subj="case-table-column-state"]`) + .first() + .text() + ).toEqual(useGetCasesMockState.data.cases[0].state); + expect( + wrapper + .find(`span[data-test-subj="case-table-column-tags-0"]`) + .first() + .prop('title') + ).toEqual(useGetCasesMockState.data.cases[0].tags[0]); + expect( + wrapper + .find(`[data-test-subj="case-table-column-username"]`) + .first() + .text() + ).toEqual(useGetCasesMockState.data.cases[0].createdBy.username); + expect( + wrapper + .find(`[data-test-subj="case-table-column-createdAt"]`) + .first() + .prop('value') + ).toEqual(useGetCasesMockState.data.cases[0].createdAt); + expect( + wrapper + .find(`[data-test-subj="case-table-column-updatedAt"]`) + .first() + .prop('value') + ).toEqual(useGetCasesMockState.data.cases[0].updatedAt); + + expect( + wrapper + .find(`[data-test-subj="case-table-case-count"]`) + .first() + .text() + ).toEqual('Showing 10 cases'); + }); + it('should tableHeaderSortButton AllCases', () => { + const wrapper = mount( + + + + ); + wrapper + .find('[data-test-subj="tableHeaderCell_state_5"] [data-test-subj="tableHeaderSortButton"]') + .simulate('click'); + expect(setQueryParams).toBeCalledWith({ + page: 1, + perPage: 5, + sortField: 'state', + sortOrder: 'asc', + }); + }); +}); diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/index.tsx index b1dd39c95e191..3253a036c2990 100644 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/all_cases/index.tsx @@ -18,7 +18,6 @@ import * as i18n from './translations'; import { getCasesColumns } from './columns'; import { SortFieldCase, Case, FilterOptions } from '../../../../containers/case/types'; -import { Direction } from '../../../../graphql/types'; import { useGetCases } from '../../../../containers/case/use_get_cases'; import { EuiBasicTableOnChange } from '../../../detection_engine/rules/types'; import { Panel } from '../../../../components/panel'; @@ -32,7 +31,16 @@ import { UtilityBarText, } from '../../../../components/detection_engine/utility_bar'; import { getCreateCaseUrl } from '../../../../components/link_to'; - +const getSortField = (field: string): SortFieldCase => { + if (field === SortFieldCase.createdAt) { + return SortFieldCase.createdAt; + } else if (field === SortFieldCase.state) { + return SortFieldCase.state; + } else if (field === SortFieldCase.updatedAt) { + return SortFieldCase.updatedAt; + } + return SortFieldCase.createdAt; +}; export const AllCases = React.memo(() => { const [ { data, isLoading, queryParams, filterOptions }, @@ -44,24 +52,10 @@ export const AllCases = React.memo(() => { ({ page, sort }: EuiBasicTableOnChange) => { let newQueryParams = queryParams; if (sort) { - let newSort; - switch (sort.field) { - case 'state': - newSort = SortFieldCase.state; - break; - case 'created_at': - newSort = SortFieldCase.createdAt; - break; - case 'updated_at': - newSort = SortFieldCase.updatedAt; - break; - default: - newSort = SortFieldCase.createdAt; - } newQueryParams = { ...newQueryParams, - sortField: newSort, - sortOrder: sort.direction as Direction, + sortField: getSortField(sort.field), + sortOrder: sort.direction, }; } if (page) { @@ -114,7 +108,9 @@ export const AllCases = React.memo(() => { - {i18n.SHOWING_CASES(data.total ?? 0)} + + {i18n.SHOWING_CASES(data.total ?? 0)} + diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/__mock__/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/__mock__/index.tsx new file mode 100644 index 0000000000000..7480c4fc4bb2a --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/__mock__/index.tsx @@ -0,0 +1,34 @@ +/* + * 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 { CaseProps } from '../index'; +import { Case } from '../../../../../containers/case/types'; + +export const caseProps: CaseProps = { + caseId: '3c4ddcc0-4e99-11ea-9290-35d05cb55c15', + initialData: { + caseId: '3c4ddcc0-4e99-11ea-9290-35d05cb55c15', + createdAt: '2020-02-13T19:44:23.627Z', + createdBy: { fullName: null, username: 'elastic' }, + description: 'Security banana Issue', + state: 'open', + tags: ['defacement'], + title: 'Another horrible breach!!', + updatedAt: '2020-02-19T15:02:57.995Z', + }, + isLoading: false, +}; + +export const data: Case = { + caseId: '3c4ddcc0-4e99-11ea-9290-35d05cb55c15', + createdAt: '2020-02-13T19:44:23.627Z', + createdBy: { username: 'elastic', fullName: null }, + description: 'Security banana Issue', + state: 'open', + tags: ['defacement'], + title: 'Another horrible breach!!', + updatedAt: '2020-02-19T15:02:57.995Z', +}; diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx new file mode 100644 index 0000000000000..a9e694bad705d --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx @@ -0,0 +1,82 @@ +/* + * 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 { mount } from 'enzyme'; +import { CaseComponent } from './'; +import * as apiHook from '../../../../containers/case/use_update_case'; +import { caseProps, data } from './__mock__'; +import { TestProviders } from '../../../../mock'; + +describe('CaseView ', () => { + const dispatchUpdateCaseProperty = jest.fn(); + + beforeEach(() => { + jest.resetAllMocks(); + jest.spyOn(apiHook, 'useUpdateCase').mockReturnValue([{ data }, dispatchUpdateCaseProperty]); + }); + + it('should render CaseComponent', () => { + const wrapper = mount( + + + + ); + expect( + wrapper + .find(`[data-test-subj="case-view-title"]`) + .first() + .prop('title') + ).toEqual(data.title); + expect( + wrapper + .find(`[data-test-subj="case-view-state"]`) + .first() + .text() + ).toEqual(data.state); + expect( + wrapper + .find(`[data-test-subj="case-view-tag-list"] .euiBadge__text`) + .first() + .text() + ).toEqual(data.tags[0]); + expect( + wrapper + .find(`[data-test-subj="case-view-username"]`) + .first() + .text() + ).toEqual(data.createdBy.username); + expect( + wrapper + .find(`[data-test-subj="case-view-createdAt"]`) + .first() + .prop('value') + ).toEqual(data.createdAt); + expect( + wrapper + .find(`[data-test-subj="case-view-description"]`) + .first() + .prop('raw') + ).toEqual(data.description); + }); + + it('should dispatch update state when button is toggled', () => { + const wrapper = mount( + + + + ); + + wrapper + .find('input[data-test-subj="toggle-case-state"]') + .simulate('change', { target: { value: false } }); + + expect(dispatchUpdateCaseProperty).toBeCalledWith({ + updateKey: 'state', + updateValue: 'closed', + }); + }); +}); diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.tsx index a92cf99097fce..5cd71c5855d34 100644 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.tsx @@ -60,13 +60,13 @@ const BackgroundWrapper = styled.div` `} `; -interface CasesProps { +export interface CaseProps { caseId: string; initialData: Case; isLoading: boolean; } -export const Cases = React.memo(({ caseId, initialData, isLoading }) => { +export const CaseComponent = React.memo(({ caseId, initialData, isLoading }) => { const [{ data }, dispatchUpdateCaseProperty] = useUpdateCase(caseId, initialData); const [isEditDescription, setIsEditDescription] = useState(false); const [isEditTags, setIsEditTags] = useState(false); @@ -162,14 +162,14 @@ export const Cases = React.memo(({ caseId, initialData, isLoading }) ]; const userActions = [ { - avatarName: data.created_by.username, + avatarName: data.createdBy.username, title: (

- {`${data.created_by.username}`} + {`${data.createdBy.username}`} {` ${i18n.ADDED_DESCRIPTION} `}{' '} - + {/* STEPH FIX come back and add label `on` */}

@@ -206,7 +206,7 @@ export const Cases = React.memo(({ caseId, initialData, isLoading })
) : ( - + ), }, ]; @@ -229,6 +229,7 @@ export const Cases = React.memo(({ caseId, initialData, isLoading }) href: getCaseUrl(), text: i18n.BACK_TO_ALL, }} + data-test-subj="case-view-title" titleNode={titleNode} title={title} > @@ -239,13 +240,21 @@ export const Cases = React.memo(({ caseId, initialData, isLoading }) {i18n.STATUS} - {data.state} + + {data.state} + {i18n.CASE_OPENED} - + @@ -255,6 +264,7 @@ export const Cases = React.memo(({ caseId, initialData, isLoading }) (({ caseId, initialData, isLoading }) - + { ); } - return ; + return ; }); CaseView.displayName = 'CaseView'; diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.tsx index 9fd1525003b0b..7d79e287b22e7 100644 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.tsx @@ -48,8 +48,8 @@ export const Create = React.memo(() => { } }, [form]); - if (newCase && newCase.case_id) { - return ; + if (newCase && newCase.caseId) { + return ; } return ( diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/user_list/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/user_list/index.tsx index b80ee58f8abbf..33e0a9541c5b4 100644 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/user_list/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/user_list/index.tsx @@ -42,7 +42,7 @@ const renderUsers = (users: ElasticUser[]) => {

- {username} + {username}

@@ -50,7 +50,7 @@ const renderUsers = (users: ElasticUser[]) => {
window.alert('Email clicked')} + onClick={() => {}} // TO DO iconType="email" aria-label="email" /> diff --git a/x-pack/legacy/plugins/siem/public/pages/home/home_navigations.tsx b/x-pack/legacy/plugins/siem/public/pages/home/home_navigations.tsx index 42d333f4f893e..a087dca38de00 100644 --- a/x-pack/legacy/plugins/siem/public/pages/home/home_navigations.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/home/home_navigations.tsx @@ -55,7 +55,7 @@ export const navTabs: SiemNavTab = { id: SiemPageName.case, name: i18n.CASE, href: getCaseUrl(), - disabled: true, + disabled: false, urlKey: 'case', }, }; diff --git a/x-pack/plugins/case/server/config.ts b/x-pack/plugins/case/server/config.ts index a7cb117198f9b..8ff9a793b17dc 100644 --- a/x-pack/plugins/case/server/config.ts +++ b/x-pack/plugins/case/server/config.ts @@ -7,9 +7,7 @@ import { schema, TypeOf } from '@kbn/config-schema'; export const ConfigSchema = schema.object({ - enabled: schema.boolean({ defaultValue: false }), - indexPattern: schema.string({ defaultValue: '.case-test-2' }), - secret: schema.string({ defaultValue: 'Cool secret huh?' }), + enabled: schema.boolean({ defaultValue: true }), }); export type ConfigType = TypeOf; diff --git a/x-pack/plugins/case/server/plugin.ts b/x-pack/plugins/case/server/plugin.ts index 37d087433a2ed..5ca640f0b25c3 100644 --- a/x-pack/plugins/case/server/plugin.ts +++ b/x-pack/plugins/case/server/plugin.ts @@ -34,6 +34,7 @@ export class CasePlugin { if (!config.enabled) { return; } + const service = new CaseService(this.log); this.log.debug( diff --git a/x-pack/plugins/case/server/routes/api/__tests__/update_case.test.ts b/x-pack/plugins/case/server/routes/api/__tests__/update_case.test.ts index 23283d7f8a5be..25d5cafb4bb06 100644 --- a/x-pack/plugins/case/server/routes/api/__tests__/update_case.test.ts +++ b/x-pack/plugins/case/server/routes/api/__tests__/update_case.test.ts @@ -27,7 +27,8 @@ describe('UPDATE case', () => { id: 'mock-id-1', }, body: { - state: 'closed', + case: { state: 'closed' }, + version: 'WzAsMV0=', }, }); @@ -38,6 +39,42 @@ describe('UPDATE case', () => { expect(typeof response.payload.updated_at).toBe('string'); expect(response.payload.state).toEqual('closed'); }); + it(`Fails with 409 if version does not match`, async () => { + const request = httpServerMock.createKibanaRequest({ + path: '/api/cases/{id}', + method: 'patch', + params: { + id: 'mock-id-1', + }, + body: { + case: { state: 'closed' }, + version: 'badv=', + }, + }); + + const theContext = createRouteContext(createMockSavedObjectsRepository(mockCases)); + + const response = await routeHandler(theContext, request, kibanaResponseFactory); + expect(response.status).toEqual(409); + }); + it(`Fails with 406 if updated field is unchanged`, async () => { + const request = httpServerMock.createKibanaRequest({ + path: '/api/cases/{id}', + method: 'patch', + params: { + id: 'mock-id-1', + }, + body: { + case: { state: 'open' }, + version: 'WzAsMV0=', + }, + }); + + const theContext = createRouteContext(createMockSavedObjectsRepository(mockCases)); + + const response = await routeHandler(theContext, request, kibanaResponseFactory); + expect(response.status).toEqual(406); + }); it(`Returns an error if updateCase throws`, async () => { const request = httpServerMock.createKibanaRequest({ path: '/api/cases/{id}', diff --git a/x-pack/plugins/case/server/routes/api/get_all_cases.ts b/x-pack/plugins/case/server/routes/api/get_all_cases.ts index 09075a32ac377..ba26a07dc2394 100644 --- a/x-pack/plugins/case/server/routes/api/get_all_cases.ts +++ b/x-pack/plugins/case/server/routes/api/get_all_cases.ts @@ -6,7 +6,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDeps } from '.'; -import { formatAllCases, wrapError } from './utils'; +import { formatAllCases, sortToSnake, wrapError } from './utils'; import { SavedObjectsFindOptionsSchema } from './schema'; import { AllCases } from './types'; @@ -23,7 +23,10 @@ export function initGetAllCasesApi({ caseService, router }: RouteDeps) { const args = request.query ? { client: context.core.savedObjects.client, - options: request.query, + options: { + ...request.query, + sortField: sortToSnake(request.query.sortField ?? ''), + }, } : { client: context.core.savedObjects.client, diff --git a/x-pack/plugins/case/server/routes/api/schema.ts b/x-pack/plugins/case/server/routes/api/schema.ts index 962dc474254f0..468abc8e7226f 100644 --- a/x-pack/plugins/case/server/routes/api/schema.ts +++ b/x-pack/plugins/case/server/routes/api/schema.ts @@ -41,6 +41,11 @@ export const UpdatedCaseSchema = schema.object({ title: schema.maybe(schema.string()), }); +export const UpdateCaseArguments = schema.object({ + case: UpdatedCaseSchema, + version: schema.string(), +}); + export const SavedObjectsFindOptionsSchema = schema.object({ defaultSearchOperator: schema.maybe(schema.oneOf([schema.literal('AND'), schema.literal('OR')])), fields: schema.maybe(schema.arrayOf(schema.string())), diff --git a/x-pack/plugins/case/server/routes/api/types.ts b/x-pack/plugins/case/server/routes/api/types.ts index 2d1a88bcf1429..5f1c207bf9829 100644 --- a/x-pack/plugins/case/server/routes/api/types.ts +++ b/x-pack/plugins/case/server/routes/api/types.ts @@ -32,12 +32,14 @@ export interface CaseAttributes extends NewCaseType, SavedObjectAttributes { export type FlattenedCaseSavedObject = CaseAttributes & { case_id: string; + version: string; comments: FlattenedCommentSavedObject[]; }; export type FlattenedCasesSavedObject = Array< CaseAttributes & { case_id: string; + version: string; // TO DO it is partial because we need to add it the commentCount commentCount?: number; } @@ -52,6 +54,7 @@ export interface AllCases { export type FlattenedCommentSavedObject = CommentAttributes & { comment_id: string; + version: string; // TO DO We might want to add the case_id where this comment is related too }; @@ -69,3 +72,13 @@ export interface UpdatedCaseType { title?: UpdatedCaseTyped['title']; updated_at: string; } + +export enum SortFieldCase { + createdAt = 'created_at', + state = 'state', + updatedAt = 'updated_at', +} + +export type Writable = { + -readonly [K in keyof T]: T[K]; +}; diff --git a/x-pack/plugins/case/server/routes/api/update_case.ts b/x-pack/plugins/case/server/routes/api/update_case.ts index 2a814c7259e4a..1c1a56dfe9b3a 100644 --- a/x-pack/plugins/case/server/routes/api/update_case.ts +++ b/x-pack/plugins/case/server/routes/api/update_case.ts @@ -5,9 +5,17 @@ */ import { schema } from '@kbn/config-schema'; +import { SavedObject } from 'kibana/server'; +import Boom from 'boom'; +import { difference } from 'lodash'; import { wrapError } from './utils'; import { RouteDeps } from '.'; -import { UpdatedCaseSchema } from './schema'; +import { UpdateCaseArguments } from './schema'; +import { CaseAttributes, UpdatedCaseTyped, Writable } from './types'; + +interface UpdateCase extends Writable { + [key: string]: any; +} export function initUpdateCaseApi({ caseService, router }: RouteDeps) { router.patch( @@ -17,23 +25,70 @@ export function initUpdateCaseApi({ caseService, router }: RouteDeps) { params: schema.object({ id: schema.string(), }), - body: UpdatedCaseSchema, + body: UpdateCaseArguments, }, }, async (context, request, response) => { + let theCase: SavedObject; try { - const updatedCase = await caseService.updateCase({ + theCase = await caseService.getCase({ client: context.core.savedObjects.client, caseId: request.params.id, - updatedAttributes: { - ...request.body, - updated_at: new Date().toISOString(), - }, }); - return response.ok({ body: updatedCase.attributes }); } catch (error) { return response.customError(wrapError(error)); } + + if (request.body.version !== theCase.version) { + return response.customError( + wrapError( + Boom.conflict( + 'This case has been updated. Please refresh before saving additional updates.' + ) + ) + ); + } + const currentCase = theCase.attributes; + const updateCase: Partial = Object.entries(request.body.case).reduce( + (acc, [key, value]) => { + const currentValue = currentCase[key]; + if ( + Array.isArray(value) && + Array.isArray(currentValue) && + difference(value, currentValue).length !== 0 + ) { + return { + ...acc, + [key]: value, + }; + } else if (value !== currentCase[key]) { + return { + ...acc, + [key]: value, + }; + } + return acc; + }, + {} + ); + if (Object.keys(updateCase).length > 0) { + try { + const updatedCase = await caseService.updateCase({ + client: context.core.savedObjects.client, + caseId: request.params.id, + updatedAttributes: { + ...updateCase, + updated_at: new Date().toISOString(), + }, + }); + return response.ok({ body: { ...updatedCase.attributes, version: updatedCase.version } }); + } catch (error) { + return response.customError(wrapError(error)); + } + } + return response.customError( + wrapError(Boom.notAcceptable('All update fields are identical to current version.')) + ); } ); } diff --git a/x-pack/plugins/case/server/routes/api/utils.ts b/x-pack/plugins/case/server/routes/api/utils.ts index 51944b04836ab..32de41e1c01c5 100644 --- a/x-pack/plugins/case/server/routes/api/utils.ts +++ b/x-pack/plugins/case/server/routes/api/utils.ts @@ -20,6 +20,7 @@ import { AllCases, NewCaseType, NewCommentType, + SortFieldCase, UserType, } from './types'; @@ -80,6 +81,7 @@ export const flattenCaseSavedObject = ( comments: Array> ): FlattenedCaseSavedObject => ({ case_id: savedObject.id, + version: savedObject.version ? savedObject.version : '0', comments: flattenCommentSavedObjects(comments), ...savedObject.attributes, }); @@ -107,5 +109,21 @@ export const flattenCommentSavedObject = ( savedObject: SavedObject ): FlattenedCommentSavedObject => ({ comment_id: savedObject.id, + version: savedObject.version ? savedObject.version : '0', ...savedObject.attributes, }); + +export const sortToSnake = (sortField: string): SortFieldCase => { + switch (sortField) { + case 'state': + return SortFieldCase.state; + case 'createdAt': + case 'created_at': + return SortFieldCase.createdAt; + case 'updatedAt': + case 'updated_at': + return SortFieldCase.updatedAt; + default: + return SortFieldCase.createdAt; + } +}; From db0a9cc61ef78b7865e74862895a5b63fe50154e Mon Sep 17 00:00:00 2001 From: Maryia Lapata Date: Mon, 24 Feb 2020 14:03:16 +0300 Subject: [PATCH 018/123] [Bug fix] Update nav link when it belongs to the same plugin (#58008) * Update nav link when it belongs to the same plugin * Move the plugin name check to history listener * Add isUrlBelongsToApp function * Code review comments * Update unit tests Co-authored-by: Elastic Machine --- .../dashboard/np_ready/dashboard_constants.ts | 2 + .../kibana/public/dashboard/plugin.ts | 15 +++- .../url/kbn_url_tracker.test.ts | 79 ++++++++++++++----- .../state_management/url/kbn_url_tracker.ts | 19 ++++- 4 files changed, 89 insertions(+), 26 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_constants.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_constants.ts index fe42e07912799..0820ebd371004 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_constants.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_constants.ts @@ -23,6 +23,8 @@ export const DashboardConstants = { CREATE_NEW_DASHBOARD_URL: '/dashboard', ADD_EMBEDDABLE_ID: 'addEmbeddableId', ADD_EMBEDDABLE_TYPE: 'addEmbeddableType', + DASHBOARDS_ID: 'dashboards', + DASHBOARD_ID: 'dashboard', }; export function createDashboardEditUrl(id: string) { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts index 7d330676e79ed..7d64ee969212f 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts @@ -83,7 +83,14 @@ export class DashboardPlugin implements Plugin { ); const { appMounted, appUnMounted, stop: stopUrlTracker } = createKbnUrlTracker({ baseUrl: core.http.basePath.prepend('/app/kibana'), - defaultSubUrl: '#/dashboards', + defaultSubUrl: `#${DashboardConstants.LANDING_PAGE_PATH}`, + shouldTrackUrlUpdate: pathname => { + const targetAppName = pathname.split('/')[1]; + return ( + targetAppName === DashboardConstants.DASHBOARDS_ID || + targetAppName === DashboardConstants.DASHBOARD_ID + ); + }, storageKey: 'lastUrl:dashboard', navLinkUpdater$: this.appStateUpdater, toastNotifications: core.notifications.toasts, @@ -150,15 +157,15 @@ export class DashboardPlugin implements Plugin { }; kibanaLegacy.registerLegacyApp({ ...app, - id: 'dashboard', + id: DashboardConstants.DASHBOARD_ID, // only register the updater in once app, otherwise all updates would happen twice updater$: this.appStateUpdater.asObservable(), navLinkId: 'kibana:dashboard', }); - kibanaLegacy.registerLegacyApp({ ...app, id: 'dashboards' }); + kibanaLegacy.registerLegacyApp({ ...app, id: DashboardConstants.DASHBOARDS_ID }); home.featureCatalogue.register({ - id: 'dashboard', + id: DashboardConstants.DASHBOARD_ID, title: i18n.translate('kbn.dashboard.featureCatalogue.dashboardTitle', { defaultMessage: 'Dashboard', }), diff --git a/src/plugins/kibana_utils/public/state_management/url/kbn_url_tracker.test.ts b/src/plugins/kibana_utils/public/state_management/url/kbn_url_tracker.test.ts index 4cf74d991ceb9..701154c06a2ff 100644 --- a/src/plugins/kibana_utils/public/state_management/url/kbn_url_tracker.test.ts +++ b/src/plugins/kibana_utils/public/state_management/url/kbn_url_tracker.test.ts @@ -38,7 +38,7 @@ describe('kbnUrlTracker', () => { let navLinkUpdaterSubject: BehaviorSubject<(app: AppBase) => { activeUrl?: string } | undefined>; let toastService: jest.Mocked; - function createTracker() { + function createTracker(shouldTrackUrlUpdate?: (pathname: string) => boolean) { urlTracker = createKbnUrlTracker({ baseUrl: '/app/test', defaultSubUrl: '#/start', @@ -57,6 +57,7 @@ describe('kbnUrlTracker', () => { ], navLinkUpdater$: navLinkUpdaterSubject, toastNotifications: toastService, + shouldTrackUrlUpdate, }); } @@ -82,44 +83,44 @@ describe('kbnUrlTracker', () => { }); test('set nav link to session storage value if defined', () => { - storage.setItem('storageKey', '#/deep/path'); + storage.setItem('storageKey', '#/start/deep/path'); createTracker(); - expect(getActiveNavLinkUrl()).toEqual('/app/test#/deep/path'); + expect(getActiveNavLinkUrl()).toEqual('/app/test#/start/deep/path'); }); test('set nav link to default if app gets mounted', () => { - storage.setItem('storageKey', '#/deep/path'); + storage.setItem('storageKey', '#/start/deep/path'); createTracker(); urlTracker.appMounted(); expect(getActiveNavLinkUrl()).toEqual('/app/test#/start'); }); test('keep nav link to default if path gets changed while app mounted', () => { - storage.setItem('storageKey', '#/deep/path'); + storage.setItem('storageKey', '#/start/deep/path'); createTracker(); urlTracker.appMounted(); - history.push('/deep/path/2'); + history.push('/start/deep/path/2'); expect(getActiveNavLinkUrl()).toEqual('/app/test#/start'); }); test('change nav link to last visited url within app after unmount', () => { createTracker(); urlTracker.appMounted(); - history.push('/deep/path/2'); - history.push('/deep/path/3'); + history.push('/start/deep/path/2'); + history.push('/start/deep/path/3'); urlTracker.appUnMounted(); - expect(getActiveNavLinkUrl()).toEqual('/app/test#/deep/path/3'); + expect(getActiveNavLinkUrl()).toEqual('/app/test#/start/deep/path/3'); }); test('unhash all urls that are recorded while app is mounted', () => { (unhashUrl as jest.Mock).mockImplementation(x => x + '?unhashed'); createTracker(); urlTracker.appMounted(); - history.push('/deep/path/2'); - history.push('/deep/path/3'); + history.push('/start/deep/path/2'); + history.push('/start/deep/path/3'); urlTracker.appUnMounted(); expect(unhashUrl).toHaveBeenCalledTimes(2); - expect(getActiveNavLinkUrl()).toEqual('/app/test#/deep/path/3?unhashed'); + expect(getActiveNavLinkUrl()).toEqual('/app/test#/start/deep/path/3?unhashed'); }); test('show warning and use hashed url if unhashing does not work', () => { @@ -128,17 +129,17 @@ describe('kbnUrlTracker', () => { }); createTracker(); urlTracker.appMounted(); - history.push('/deep/path/2'); + history.push('/start/deep/path/2'); urlTracker.appUnMounted(); - expect(getActiveNavLinkUrl()).toEqual('/app/test#/deep/path/2'); + expect(getActiveNavLinkUrl()).toEqual('/app/test#/start/deep/path/2'); expect(toastService.addDanger).toHaveBeenCalledWith('unhash broke'); }); test('change nav link back to default if app gets mounted again', () => { createTracker(); urlTracker.appMounted(); - history.push('/deep/path/2'); - history.push('/deep/path/3'); + history.push('/start/deep/path/2'); + history.push('/start/deep/path/3'); urlTracker.appUnMounted(); urlTracker.appMounted(); expect(getActiveNavLinkUrl()).toEqual('/app/test#/start'); @@ -151,11 +152,11 @@ describe('kbnUrlTracker', () => { }); test('update state param without overwriting rest of the url when app is not mounted', () => { - storage.setItem('storageKey', '#/deep/path?extrastate=1'); + storage.setItem('storageKey', '#/start/deep/path?extrastate=1'); createTracker(); state1Subject.next({ key1: 'abc' }); expect(getActiveNavLinkUrl()).toMatchInlineSnapshot( - `"/app/test#/deep/path?extrastate=1&state1=(key1:abc)"` + `"/app/test#/start/deep/path?extrastate=1&state1=(key1:abc)"` ); }); @@ -184,7 +185,45 @@ describe('kbnUrlTracker', () => { test('set url to storage when setActiveUrl was called', () => { createTracker(); - urlTracker.setActiveUrl('/deep/path/4'); - expect(storage.getItem('storageKey')).toEqual('#/deep/path/4'); + urlTracker.setActiveUrl('/start/deep/path/4'); + expect(storage.getItem('storageKey')).toEqual('#/start/deep/path/4'); + }); + + describe('shouldTrackUrlUpdate', () => { + test('change nav link when shouldTrackUrlUpdate is not overridden', () => { + storage.setItem('storageKey', '#/start/deep/path'); + createTracker(); + urlTracker.appMounted(); + history.push('/start/path'); + urlTracker.appUnMounted(); + expect(getActiveNavLinkUrl()).toEqual('/app/test#/start/path'); + }); + + test('not change nav link when shouldTrackUrlUpdate is not overridden', () => { + storage.setItem('storageKey', '#/start/deep/path'); + createTracker(); + urlTracker.appMounted(); + history.push('/setup/path/2'); + urlTracker.appUnMounted(); + expect(getActiveNavLinkUrl()).toEqual('/app/test#/start/deep/path'); + }); + + test('change nav link when shouldTrackUrlUpdate is overridden', () => { + storage.setItem('storageKey', '#/start/deep/path'); + createTracker(() => true); + urlTracker.appMounted(); + history.push('/setup/path/2'); + urlTracker.appUnMounted(); + expect(getActiveNavLinkUrl()).toEqual('/app/test#/setup/path/2'); + }); + + test('not change nav link when shouldTrackUrlUpdate is overridden', () => { + storage.setItem('storageKey', '#/start/deep/path'); + createTracker(() => false); + urlTracker.appMounted(); + history.push('/setup/path/2'); + urlTracker.appUnMounted(); + expect(getActiveNavLinkUrl()).toEqual('/app/test#/start/deep/path'); + }); }); }); diff --git a/src/plugins/kibana_utils/public/state_management/url/kbn_url_tracker.ts b/src/plugins/kibana_utils/public/state_management/url/kbn_url_tracker.ts index 2edd135c184ec..b778535a2d428 100644 --- a/src/plugins/kibana_utils/public/state_management/url/kbn_url_tracker.ts +++ b/src/plugins/kibana_utils/public/state_management/url/kbn_url_tracker.ts @@ -58,6 +58,12 @@ export function createKbnUrlTracker({ toastNotifications, history, storage, + shouldTrackUrlUpdate = pathname => { + const currentAppName = defaultSubUrl.slice(2); // cut hash and slash symbols + const targetAppName = pathname.split('/')[1]; + + return currentAppName === targetAppName; + }, }: { /** * Base url of the current app. This will be used as a prefix for the @@ -82,7 +88,7 @@ export function createKbnUrlTracker({ stateUpdate$: Observable; }>; /** - * Key used to store the current sub url in session storage. This key should only be used for one active url tracker at any given ntime. + * Key used to store the current sub url in session storage. This key should only be used for one active url tracker at any given time. */ storageKey: string; /** @@ -101,6 +107,13 @@ export function createKbnUrlTracker({ * Storage object to use to persist currently active url. If this isn't provided, the browser wide session storage instance will be used. */ storage?: Storage; + /** + * Checks if pathname belongs to current app. It's used in history listener to define whether it's necessary to set pathname as active url or not. + * The default implementation compares the app name to the first part of pathname. Consumers can override this function for more complex cases. + * + * @param {string} pathname A location's pathname which comes to history listener + */ + shouldTrackUrlUpdate?: (pathname: string) => boolean; }): KbnUrlTracker { const historyInstance = history || createHashHistory(); const storageInstance = storage || sessionStorage; @@ -148,7 +161,9 @@ export function createKbnUrlTracker({ unsubscribe(); // track current hash when within app unsubscribeURLHistory = historyInstance.listen(location => { - setActiveUrl(location.pathname + location.search); + if (shouldTrackUrlUpdate(location.pathname)) { + setActiveUrl(location.pathname + location.search); + } }); } From e64eff0a3d5fde205256ab74b731a63766822f9a Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Mon, 24 Feb 2020 06:02:27 -0800 Subject: [PATCH 019/123] Temporarily removes kbn-optimizer cache key tests (#58318) While we investigate why they are interfering with other tests. Signed-off-by: Tyler Smalley Co-authored-by: Elastic Machine --- .../src/optimizer/cache_keys.test.ts | 206 ------------------ 1 file changed, 206 deletions(-) delete mode 100644 packages/kbn-optimizer/src/optimizer/cache_keys.test.ts diff --git a/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts b/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts deleted file mode 100644 index 2337017f54ed8..0000000000000 --- a/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts +++ /dev/null @@ -1,206 +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 Path from 'path'; - -import jestDiff from 'jest-diff'; -import { REPO_ROOT, createAbsolutePathSerializer } from '@kbn/dev-utils'; - -import { reformatJestDiff, getOptimizerCacheKey, diffCacheKey } from './cache_keys'; -import { OptimizerConfig } from './optimizer_config'; - -jest.mock('./get_changes.ts', () => ({ - getChanges: async () => - new Map([ - ['/foo/bar/a', 'modified'], - ['/foo/bar/b', 'modified'], - ['/foo/bar/c', 'deleted'], - ]), -})); - -jest.mock('./get_mtimes.ts', () => ({ - getMtimes: async (paths: string[]) => new Map(paths.map(path => [path, 12345])), -})); - -jest.mock('execa'); - -jest.mock('fs', () => { - const realFs = jest.requireActual('fs'); - jest.spyOn(realFs, 'readFile'); - return realFs; -}); - -expect.addSnapshotSerializer(createAbsolutePathSerializer()); - -jest.requireMock('execa').mockImplementation(async (cmd: string, args: string[], opts: object) => { - expect(cmd).toBe('git'); - expect(args).toEqual([ - 'log', - '-n', - '1', - '--pretty=format:%H', - '--', - expect.stringContaining('kbn-optimizer'), - ]); - expect(opts).toEqual({ - cwd: REPO_ROOT, - }); - - return { - stdout: '', - }; -}); - -describe('getOptimizerCacheKey()', () => { - it('uses latest commit, bootstrap cache, and changed files to create unique value', async () => { - jest - .requireMock('fs') - .readFile.mockImplementation( - (path: string, enc: string, cb: (err: null, file: string) => void) => { - expect(path).toBe( - Path.resolve(REPO_ROOT, 'packages/kbn-optimizer/target/.bootstrap-cache') - ); - expect(enc).toBe('utf8'); - cb(null, ''); - } - ); - - const config = OptimizerConfig.create({ - repoRoot: REPO_ROOT, - }); - - await expect(getOptimizerCacheKey(config)).resolves.toMatchInlineSnapshot(` - Object { - "bootstrap": "", - "deletedPaths": Array [ - "/foo/bar/c", - ], - "lastCommit": "", - "modifiedTimes": Object { - "/foo/bar/a": 12345, - "/foo/bar/b": 12345, - }, - "workerConfig": Object { - "browserslistEnv": "dev", - "cache": true, - "dist": false, - "optimizerCacheKey": "♻", - "profileWebpack": false, - "repoRoot": , - "watch": false, - }, - } - `); - }); -}); - -describe('diffCacheKey()', () => { - it('returns undefined if values are equal', () => { - expect(diffCacheKey('1', '1')).toBe(undefined); - expect(diffCacheKey(1, 1)).toBe(undefined); - expect(diffCacheKey(['1', '2', { a: 'b' }], ['1', '2', { a: 'b' }])).toBe(undefined); - expect( - diffCacheKey( - { - a: '1', - b: '2', - }, - { - b: '2', - a: '1', - } - ) - ).toBe(undefined); - }); - - it('returns a diff if the values are different', () => { - expect(diffCacheKey(['1', '2', { a: 'b' }], ['1', '2', { b: 'a' }])).toMatchInlineSnapshot(` - "- Expected - + Received - -  Array [ -  \\"1\\", -  \\"2\\", -  Object { - - \\"a\\": \\"b\\", - + \\"b\\": \\"a\\", -  }, -  ]" - `); - expect( - diffCacheKey( - { - a: '1', - b: '1', - }, - { - b: '2', - a: '2', - } - ) - ).toMatchInlineSnapshot(` - "- Expected - + Received - -  Object { - - \\"a\\": \\"1\\", - - \\"b\\": \\"1\\", - + \\"a\\": \\"2\\", - + \\"b\\": \\"2\\", -  }" - `); - }); -}); - -describe('reformatJestDiff()', () => { - it('reformats large jestDiff output to focus on the changed lines', () => { - const diff = jestDiff( - { - a: ['1', '1', '1', '1', '1', '1', '1', '2', '1', '1', '1', '1', '1', '1', '1', '1', '1'], - }, - { - b: ['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '1', '1', '1', '1'], - } - ); - - expect(reformatJestDiff(diff)).toMatchInlineSnapshot(` - "- Expected - + Received - -  Object { - - \\"a\\": Array [ - + \\"b\\": Array [ -  \\"1\\", -  \\"1\\", -  ... -  \\"1\\", -  \\"1\\", - - \\"2\\", -  \\"1\\", -  \\"1\\", -  ... -  \\"1\\", -  \\"1\\", - + \\"2\\", -  \\"1\\", -  \\"1\\", -  ..." - `); - }); -}); From 581f1bd6e9329b66db5bc3cb3348475595db5aa2 Mon Sep 17 00:00:00 2001 From: Vadim Dalecky Date: Mon, 24 Feb 2020 16:26:34 +0100 Subject: [PATCH 020/123] Expressions debug mode (#57841) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 add ability to execute expression in debug mode * feat: 🎸 store resolved arguments in debug information * feat: 🎸 track function execution time and set "success" flag * feat: 🎸 store debug information for functions that throw * feat: 🎸 use performance.now, safe "fn" reference, fix typo --- src/plugins/expressions/common/ast/types.ts | 53 ++++ .../common/execution/execution.test.ts | 253 +++++++++++++++++- .../expressions/common/execution/execution.ts | 67 ++++- .../expressions/common/executor/executor.ts | 26 +- 4 files changed, 379 insertions(+), 20 deletions(-) diff --git a/src/plugins/expressions/common/ast/types.ts b/src/plugins/expressions/common/ast/types.ts index 82a7578dd4b89..0b505f117a580 100644 --- a/src/plugins/expressions/common/ast/types.ts +++ b/src/plugins/expressions/common/ast/types.ts @@ -17,6 +17,9 @@ * under the License. */ +import { ExpressionValue, ExpressionValueError } from '../expression_types'; +import { ExpressionFunction } from '../../public'; + export type ExpressionAstNode = | ExpressionAstExpression | ExpressionAstFunction @@ -31,6 +34,56 @@ export interface ExpressionAstFunction { type: 'function'; function: string; arguments: Record; + + /** + * Debug information added to each function when expression is executed in *debug mode*. + */ + debug?: ExpressionAstFunctionDebug; +} + +export interface ExpressionAstFunctionDebug { + /** + * True if function successfully returned output, false if function threw. + */ + success: boolean; + + /** + * Reference to the expression function this AST node represents. + */ + fn: ExpressionFunction; + + /** + * Input that expression function received as its first argument. + */ + input: ExpressionValue; + + /** + * Map of resolved arguments expression function received as its second argument. + */ + args: Record; + + /** + * Result returned by the expression function. Including an error result + * if it was returned by the function (not thrown). + */ + output?: ExpressionValue; + + /** + * Error that function threw normalized to `ExpressionValueError`. + */ + error?: ExpressionValueError; + + /** + * Raw error that was thrown by the function, if any. + */ + rawError?: any | Error; + + /** + * Time in milliseconds it took to execute the function. Duration can be + * `undefined` if error happened during argument resolution, because function + * timing starts after the arguments have been resolved. + */ + duration: number | undefined; } export type ExpressionAstArgument = string | boolean | number | ExpressionAstExpression; diff --git a/src/plugins/expressions/common/execution/execution.test.ts b/src/plugins/expressions/common/execution/execution.test.ts index b6c1721e33eef..f6ff9efca848b 100644 --- a/src/plugins/expressions/common/execution/execution.test.ts +++ b/src/plugins/expressions/common/execution/execution.test.ts @@ -18,20 +18,28 @@ */ import { Execution } from './execution'; -import { parseExpression } from '../ast'; +import { parseExpression, ExpressionAstExpression } from '../ast'; import { createUnitTestExecutor } from '../test_helpers'; import { ExpressionFunctionDefinition } from '../../public'; import { ExecutionContract } from './execution_contract'; +beforeAll(() => { + if (typeof performance === 'undefined') { + (global as any).performance = { now: Date.now }; + } +}); + const createExecution = ( expression: string = 'foo bar=123', - context: Record = {} + context: Record = {}, + debug: boolean = false ) => { const executor = createUnitTestExecutor(); const execution = new Execution({ executor, ast: parseExpression(expression), context, + debug, }); return execution; }; @@ -406,4 +414,245 @@ describe('Execution', () => { }); }); }); + + describe('debug mode', () => { + test('can execute expression in debug mode', async () => { + const execution = createExecution('add val=1 | add val=2 | add val=3', {}, true); + execution.start(-1); + const result = await execution.result; + + expect(result).toEqual({ + type: 'num', + value: 5, + }); + }); + + test('can execute expression with sub-expression in debug mode', async () => { + const execution = createExecution( + 'add val={var_set name=foo value=5 | var name=foo} | add val=10', + {}, + true + ); + execution.start(0); + const result = await execution.result; + + expect(result).toEqual({ + type: 'num', + value: 15, + }); + }); + + describe('when functions succeed', () => { + test('sets "success" flag on all functions to true', async () => { + const execution = createExecution('add val=1 | add val=2 | add val=3', {}, true); + execution.start(-1); + await execution.result; + + for (const node of execution.state.get().ast.chain) { + expect(node.debug?.success).toBe(true); + } + }); + + test('stores "fn" reference to the function', async () => { + const execution = createExecution('add val=1 | add val=2 | add val=3', {}, true); + execution.start(-1); + await execution.result; + + for (const node of execution.state.get().ast.chain) { + expect(node.debug?.fn.name).toBe('add'); + } + }); + + test('saves duration it took to execute each function', async () => { + const execution = createExecution('add val=1 | add val=2 | add val=3', {}, true); + execution.start(-1); + await execution.result; + + for (const node of execution.state.get().ast.chain) { + expect(typeof node.debug?.duration).toBe('number'); + expect(node.debug?.duration).toBeLessThan(100); + expect(node.debug?.duration).toBeGreaterThanOrEqual(0); + } + }); + + test('sets duration to 10 milliseconds when function executes 10 milliseconds', async () => { + const execution = createExecution('sleep 10', {}, true); + execution.start(-1); + await execution.result; + + const node = execution.state.get().ast.chain[0]; + expect(typeof node.debug?.duration).toBe('number'); + expect(node.debug?.duration).toBeLessThan(50); + expect(node.debug?.duration).toBeGreaterThanOrEqual(5); + }); + + test('adds .debug field in expression AST on each executed function', async () => { + const execution = createExecution('add val=1 | add val=2 | add val=3', {}, true); + execution.start(-1); + await execution.result; + + for (const node of execution.state.get().ast.chain) { + expect(typeof node.debug).toBe('object'); + expect(!!node.debug).toBe(true); + } + }); + + test('stores input of each function', async () => { + const execution = createExecution('add val=1 | add val=2 | add val=3', {}, true); + execution.start(-1); + await execution.result; + + const { chain } = execution.state.get().ast; + + expect(chain[0].debug!.input).toBe(-1); + expect(chain[1].debug!.input).toEqual({ + type: 'num', + value: 0, + }); + expect(chain[2].debug!.input).toEqual({ + type: 'num', + value: 2, + }); + }); + + test('stores output of each function', async () => { + const execution = createExecution('add val=1 | add val=2 | add val=3', {}, true); + execution.start(-1); + await execution.result; + + const { chain } = execution.state.get().ast; + + expect(chain[0].debug!.output).toEqual({ + type: 'num', + value: 0, + }); + expect(chain[1].debug!.output).toEqual({ + type: 'num', + value: 2, + }); + expect(chain[2].debug!.output).toEqual({ + type: 'num', + value: 5, + }); + }); + + test('stores resolved arguments of a function', async () => { + const execution = createExecution( + 'add val={var_set name=foo value=5 | var name=foo} | add val=10', + {}, + true + ); + execution.start(-1); + await execution.result; + + const { chain } = execution.state.get().ast; + + expect(chain[0].debug!.args).toEqual({ + val: 5, + }); + + expect((chain[0].arguments.val[0] as ExpressionAstExpression).chain[0].debug!.args).toEqual( + { + name: 'foo', + value: 5, + } + ); + }); + + test('store debug information about sub-expressions', async () => { + const execution = createExecution( + 'add val={var_set name=foo value=5 | var name=foo} | add val=10', + {}, + true + ); + execution.start(0); + await execution.result; + + const { chain } = execution.state.get().ast.chain[0].arguments + .val[0] as ExpressionAstExpression; + + expect(typeof chain[0].debug).toBe('object'); + expect(typeof chain[1].debug).toBe('object'); + expect(!!chain[0].debug).toBe(true); + expect(!!chain[1].debug).toBe(true); + + expect(chain[0].debug!.input).toBe(0); + expect(chain[0].debug!.output).toBe(0); + expect(chain[1].debug!.input).toBe(0); + expect(chain[1].debug!.output).toBe(5); + }); + }); + + describe('when expression throws', () => { + const executor = createUnitTestExecutor(); + executor.registerFunction({ + name: 'throws', + args: {}, + help: '', + fn: () => { + throw new Error('foo'); + }, + }); + + test('stores debug information up until the function that throws', async () => { + const execution = new Execution({ + executor, + ast: parseExpression('add val=1 | throws | add val=3'), + debug: true, + }); + execution.start(0); + await execution.result; + + const node1 = execution.state.get().ast.chain[0]; + const node2 = execution.state.get().ast.chain[1]; + const node3 = execution.state.get().ast.chain[2]; + + expect(typeof node1.debug).toBe('object'); + expect(typeof node2.debug).toBe('object'); + expect(typeof node3.debug).toBe('undefined'); + }); + + test('stores error thrown in debug information', async () => { + const execution = new Execution({ + executor, + ast: parseExpression('add val=1 | throws | add val=3'), + debug: true, + }); + execution.start(0); + await execution.result; + + const node2 = execution.state.get().ast.chain[1]; + + expect(node2.debug?.error).toMatchObject({ + type: 'error', + error: { + message: '[throws] > foo', + }, + }); + expect(node2.debug?.rawError).toBeInstanceOf(Error); + }); + + test('sets .debug object to expected shape', async () => { + const execution = new Execution({ + executor, + ast: parseExpression('add val=1 | throws | add val=3'), + debug: true, + }); + execution.start(0); + await execution.result; + + const node2 = execution.state.get().ast.chain[1]; + + expect(node2.debug).toMatchObject({ + success: false, + fn: expect.any(Object), + input: expect.any(Object), + args: expect.any(Object), + error: expect.any(Object), + rawError: expect.any(Error), + duration: expect.any(Number), + }); + }); + }); + }); }); diff --git a/src/plugins/expressions/common/execution/execution.ts b/src/plugins/expressions/common/execution/execution.ts index 2a272e187cffc..7e7df822724ae 100644 --- a/src/plugins/expressions/common/execution/execution.ts +++ b/src/plugins/expressions/common/execution/execution.ts @@ -23,7 +23,7 @@ import { createExecutionContainer, ExecutionContainer } from './container'; import { createError } from '../util'; import { Defer } from '../../../kibana_utils/common'; import { RequestAdapter, DataAdapter } from '../../../inspector/common'; -import { isExpressionValueError } from '../expression_types/specs/error'; +import { isExpressionValueError, ExpressionValueError } from '../expression_types/specs/error'; import { ExpressionAstExpression, ExpressionAstFunction, @@ -32,7 +32,7 @@ import { parseExpression, } from '../ast'; import { ExecutionContext, DefaultInspectorAdapters } from './types'; -import { getType } from '../expression_types'; +import { getType, ExpressionValue } from '../expression_types'; import { ArgumentType, ExpressionFunction } from '../expression_functions'; import { getByAlias } from '../util/get_by_alias'; import { ExecutionContract } from './execution_contract'; @@ -44,6 +44,13 @@ export interface ExecutionParams< ast?: ExpressionAstExpression; expression?: string; context?: ExtraContext; + + /** + * Whether to execute expression in *debug mode*. In *debug mode* inputs and + * outputs as well as all resolved arguments and time it took to execute each + * function are saved and are available for introspection. + */ + debug?: boolean; } const createDefaultInspectorAdapters = (): DefaultInspectorAdapters => ({ @@ -190,23 +197,55 @@ export class Execution< } const { function: fnName, arguments: fnArgs } = link; - const fnDef = getByAlias(this.state.get().functions, fnName); + const fn = getByAlias(this.state.get().functions, fnName); - if (!fnDef) { + if (!fn) { return createError({ message: `Function ${fnName} could not be found.` }); } + let args: Record = {}; + let timeStart: number | undefined; + try { - // Resolve arguments before passing to function - // resolveArgs returns an object because the arguments themselves might - // actually have a 'then' function which would be treated as a promise - const { resolvedArgs } = await this.resolveArgs(fnDef, input, fnArgs); - const output = await this.invokeFunction(fnDef, input, resolvedArgs); + // `resolveArgs` returns an object because the arguments themselves might + // actually have a `then` function which would be treated as a `Promise`. + const { resolvedArgs } = await this.resolveArgs(fn, input, fnArgs); + args = resolvedArgs; + timeStart = this.params.debug ? performance.now() : 0; + const output = await this.invokeFunction(fn, input, resolvedArgs); + + if (this.params.debug) { + const timeEnd: number = performance.now(); + (link as ExpressionAstFunction).debug = { + success: true, + fn, + input, + args: resolvedArgs, + output, + duration: timeEnd - timeStart, + }; + } + if (getType(output) === 'error') return output; input = output; - } catch (e) { - e.message = `[${fnName}] > ${e.message}`; - return createError(e); + } catch (rawError) { + const timeEnd: number = this.params.debug ? performance.now() : 0; + rawError.message = `[${fnName}] > ${rawError.message}`; + const error = createError(rawError) as ExpressionValueError; + + if (this.params.debug) { + (link as ExpressionAstFunction).debug = { + success: false, + fn, + input, + args, + error, + rawError, + duration: timeStart ? timeEnd - timeStart : undefined, + }; + } + + return error; } } @@ -327,7 +366,9 @@ export class Execution< const resolveArgFns = mapValues(argAstsWithDefaults, (asts, argName) => { return asts.map((item: ExpressionAstExpression) => { return async (subInput = input) => { - const output = await this.params.executor.interpret(item, subInput); + const output = await this.params.executor.interpret(item, subInput, { + debug: this.params.debug, + }); if (isExpressionValueError(output)) throw output.error; const casted = this.cast(output, argDefs[argName as any].types); return casted; diff --git a/src/plugins/expressions/common/executor/executor.ts b/src/plugins/expressions/common/executor/executor.ts index af3662d13de4e..2ecbc5f75a9e8 100644 --- a/src/plugins/expressions/common/executor/executor.ts +++ b/src/plugins/expressions/common/executor/executor.ts @@ -31,6 +31,15 @@ import { ExpressionAstExpression, ExpressionAstNode } from '../ast'; import { typeSpecs } from '../expression_types/specs'; import { functionSpecs } from '../expression_functions/specs'; +export interface ExpressionExecOptions { + /** + * Whether to execute expression in *debug mode*. In *debug mode* inputs and + * outputs as well as all resolved arguments and time it took to execute each + * function are saved and are available for introspection. + */ + debug?: boolean; +} + export class TypesRegistry implements IRegistry { constructor(private readonly executor: Executor) {} @@ -145,10 +154,14 @@ export class Executor = Record(ast: ExpressionAstNode, input: T): Promise { + public async interpret( + ast: ExpressionAstNode, + input: T, + options?: ExpressionExecOptions + ): Promise { switch (getType(ast)) { case 'expression': - return await this.interpretExpression(ast as ExpressionAstExpression, input); + return await this.interpretExpression(ast as ExpressionAstExpression, input, options); case 'string': case 'number': case 'null': @@ -161,9 +174,10 @@ export class Executor = Record( ast: string | ExpressionAstExpression, - input: T + input: T, + options?: ExpressionExecOptions ): Promise { - const execution = this.createExecution(ast); + const execution = this.createExecution(ast, undefined, options); execution.start(input); return await execution.result; } @@ -192,7 +206,8 @@ export class Executor = Record( ast: string | ExpressionAstExpression, - context: ExtraContext = {} as ExtraContext + context: ExtraContext = {} as ExtraContext, + { debug }: ExpressionExecOptions = {} as ExpressionExecOptions ): Execution { const params: ExecutionParams = { executor: this, @@ -200,6 +215,7 @@ export class Executor = Record Date: Mon, 24 Feb 2020 16:40:20 +0100 Subject: [PATCH 021/123] no sparse array by default. (#58212) Co-authored-by: Elastic Machine --- .../src/types/array_type.test.ts | 37 ++++++++++++++++--- .../kbn-config-schema/src/types/array_type.ts | 4 +- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/packages/kbn-config-schema/src/types/array_type.test.ts b/packages/kbn-config-schema/src/types/array_type.test.ts index 73661ef849cf4..66b72096a593d 100644 --- a/packages/kbn-config-schema/src/types/array_type.test.ts +++ b/packages/kbn-config-schema/src/types/array_type.test.ts @@ -85,14 +85,29 @@ test('fails if mixed types of content in array', () => { ); }); -test('returns empty array if input is empty but type has default value', () => { - const type = schema.arrayOf(schema.string({ defaultValue: 'test' })); +test('fails if sparse content in array', () => { + const type = schema.arrayOf(schema.string()); expect(type.validate([])).toEqual([]); + expect(() => type.validate([undefined])).toThrowErrorMatchingInlineSnapshot( + `"[0]: sparse array are not allowed"` + ); }); -test('returns empty array if input is empty even if type is required', () => { - const type = schema.arrayOf(schema.string()); +test('fails if sparse content in array if optional', () => { + const type = schema.arrayOf(schema.maybe(schema.string())); + expect(type.validate([])).toEqual([]); + expect(() => type.validate([undefined])).toThrowErrorMatchingInlineSnapshot( + `"[0]: sparse array are not allowed"` + ); +}); + +test('fails if sparse content in array if nullable', () => { + const type = schema.arrayOf(schema.nullable(schema.string())); expect(type.validate([])).toEqual([]); + expect(type.validate([null])).toEqual([null]); + expect(() => type.validate([undefined])).toThrowErrorMatchingInlineSnapshot( + `"[0]: sparse array are not allowed"` + ); }); test('fails for null values if optional', () => { @@ -102,9 +117,19 @@ test('fails for null values if optional', () => { ); }); +test('returns empty array if input is empty but type has default value', () => { + const type = schema.arrayOf(schema.string({ defaultValue: 'test' })); + expect(type.validate([])).toEqual([]); +}); + +test('returns empty array if input is empty even if type is required', () => { + const type = schema.arrayOf(schema.string()); + expect(type.validate([])).toEqual([]); +}); + test('handles default values for undefined values', () => { - const type = schema.arrayOf(schema.string({ defaultValue: 'foo' })); - expect(type.validate([undefined])).toEqual(['foo']); + const type = schema.arrayOf(schema.string(), { defaultValue: ['foo'] }); + expect(type.validate(undefined)).toEqual(['foo']); }); test('array within array', () => { diff --git a/packages/kbn-config-schema/src/types/array_type.ts b/packages/kbn-config-schema/src/types/array_type.ts index ad74f375588ad..a0353e8348ddd 100644 --- a/packages/kbn-config-schema/src/types/array_type.ts +++ b/packages/kbn-config-schema/src/types/array_type.ts @@ -31,7 +31,7 @@ export class ArrayType extends Type { let schema = internals .array() .items(type.getSchema().optional()) - .sparse(); + .sparse(false); if (options.minSize !== undefined) { schema = schema.min(options.minSize); @@ -49,6 +49,8 @@ export class ArrayType extends Type { case 'any.required': case 'array.base': return `expected value of type [array] but got [${typeDetect(value)}]`; + case 'array.sparse': + return `sparse array are not allowed`; case 'array.parse': return `could not parse array value from [${value}]`; case 'array.min': From 6b735c9ca016a65cc0c2e29fb144a1046020f1d3 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Mon, 24 Feb 2020 11:17:29 -0500 Subject: [PATCH 022/123] [ML] New Platform server shim: update usage collector to use core savedObjects (#58058) * use NP savedObjects and createInternalRepository for usage collection * fix route doc typo * update MlTelemetrySavedObject type * remove fileDataVisualizer routes dependency on legacy es plugin * update mlTelemetry tests * remove deprecated use of getSavedObjectsClient --- x-pack/legacy/plugins/ml/index.ts | 3 +- .../ml/server/lib/ml_telemetry/index.ts | 1 - .../ml_telemetry/make_ml_usage_collector.ts | 15 ++- .../lib/ml_telemetry/ml_telemetry.test.ts | 102 +++++------------- .../server/lib/ml_telemetry/ml_telemetry.ts | 39 +++---- .../plugins/ml/server/new_platform/plugin.ts | 21 ++-- .../ml/server/routes/file_data_visualizer.ts | 2 +- .../ml/server/routes/job_audit_messages.ts | 2 +- 8 files changed, 55 insertions(+), 130 deletions(-) diff --git a/x-pack/legacy/plugins/ml/index.ts b/x-pack/legacy/plugins/ml/index.ts index 0ef5e14e44f71..09f1b9ccedce4 100755 --- a/x-pack/legacy/plugins/ml/index.ts +++ b/x-pack/legacy/plugins/ml/index.ts @@ -81,7 +81,8 @@ export const ml = (kibana: any) => { injectUiAppVars: server.injectUiAppVars, http: mlHttpService, savedObjects: server.savedObjects, - elasticsearch: kbnServer.newPlatform.setup.core.elasticsearch, // NP + coreSavedObjects: kbnServer.newPlatform.start.core.savedObjects, + elasticsearch: kbnServer.newPlatform.setup.core.elasticsearch, }; const { usageCollection, cloud, home } = kbnServer.newPlatform.setup.plugins; const plugins = { diff --git a/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/index.ts b/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/index.ts index 5da4f6b62bcec..dffd95f50e0d9 100644 --- a/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/index.ts +++ b/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/index.ts @@ -6,7 +6,6 @@ export { createMlTelemetry, - getSavedObjectsClient, incrementFileDataVisualizerIndexCreationCount, storeMlTelemetry, MlTelemetry, diff --git a/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/make_ml_usage_collector.ts b/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/make_ml_usage_collector.ts index 293480b2aa5dc..a120450bbb2b0 100644 --- a/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/make_ml_usage_collector.ts +++ b/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/make_ml_usage_collector.ts @@ -5,19 +5,17 @@ */ import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { SavedObjectsServiceStart } from 'src/core/server'; import { createMlTelemetry, - getSavedObjectsClient, ML_TELEMETRY_DOC_ID, MlTelemetry, MlTelemetrySavedObject, } from './ml_telemetry'; -import { UsageInitialization } from '../../new_platform/plugin'; - export function makeMlUsageCollector( usageCollection: UsageCollectionSetup | undefined, - { elasticsearchPlugin, savedObjects }: UsageInitialization + savedObjects: SavedObjectsServiceStart ): void { if (!usageCollection) { return; @@ -28,11 +26,10 @@ export function makeMlUsageCollector( isReady: () => true, fetch: async (): Promise => { try { - const savedObjectsClient = getSavedObjectsClient(elasticsearchPlugin, savedObjects); - const mlTelemetrySavedObject = (await savedObjectsClient.get( - 'ml-telemetry', - ML_TELEMETRY_DOC_ID - )) as MlTelemetrySavedObject; + const mlTelemetrySavedObject: MlTelemetrySavedObject = await savedObjects + .createInternalRepository() + .get('ml-telemetry', ML_TELEMETRY_DOC_ID); + return mlTelemetrySavedObject.attributes; } catch (err) { return createMlTelemetry(); diff --git a/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/ml_telemetry.test.ts b/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/ml_telemetry.test.ts index fcf3763626b6f..9d14ffb31be63 100644 --- a/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/ml_telemetry.test.ts +++ b/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/ml_telemetry.test.ts @@ -6,7 +6,6 @@ import { createMlTelemetry, - getSavedObjectsClient, incrementFileDataVisualizerIndexCreationCount, ML_TELEMETRY_DOC_ID, MlTelemetry, @@ -26,22 +25,11 @@ describe('ml_telemetry', () => { }); describe('storeMlTelemetry', () => { - let elasticsearchPlugin: any; - let savedObjects: any; let mlTelemetry: MlTelemetry; - let savedObjectsClientInstance: any; + let internalRepository: any; beforeEach(() => { - savedObjectsClientInstance = { create: jest.fn() }; - const callWithInternalUser = jest.fn(); - const internalRepository = jest.fn(); - elasticsearchPlugin = { - getCluster: jest.fn(() => ({ callWithInternalUser })), - }; - savedObjects = { - SavedObjectsClient: jest.fn(() => savedObjectsClientInstance), - getSavedObjectsRepository: jest.fn(() => internalRepository), - }; + internalRepository = { create: jest.fn(), get: jest.fn() }; mlTelemetry = { file_data_visualizer: { index_creation_count: 1, @@ -49,59 +37,28 @@ describe('ml_telemetry', () => { }; }); - it('should call savedObjectsClient create with the given MlTelemetry object', () => { - storeMlTelemetry(elasticsearchPlugin, savedObjects, mlTelemetry); - expect(savedObjectsClientInstance.create.mock.calls[0][1]).toBe(mlTelemetry); + it('should call internalRepository create with the given MlTelemetry object', () => { + storeMlTelemetry(internalRepository, mlTelemetry); + expect(internalRepository.create.mock.calls[0][1]).toBe(mlTelemetry); }); - it('should call savedObjectsClient create with the ml-telemetry document type and ID', () => { - storeMlTelemetry(elasticsearchPlugin, savedObjects, mlTelemetry); - expect(savedObjectsClientInstance.create.mock.calls[0][0]).toBe('ml-telemetry'); - expect(savedObjectsClientInstance.create.mock.calls[0][2].id).toBe(ML_TELEMETRY_DOC_ID); + it('should call internalRepository create with the ml-telemetry document type and ID', () => { + storeMlTelemetry(internalRepository, mlTelemetry); + expect(internalRepository.create.mock.calls[0][0]).toBe('ml-telemetry'); + expect(internalRepository.create.mock.calls[0][2].id).toBe(ML_TELEMETRY_DOC_ID); }); - it('should call savedObjectsClient create with overwrite: true', () => { - storeMlTelemetry(elasticsearchPlugin, savedObjects, mlTelemetry); - expect(savedObjectsClientInstance.create.mock.calls[0][2].overwrite).toBe(true); - }); - }); - - describe('getSavedObjectsClient', () => { - let elasticsearchPlugin: any; - let savedObjects: any; - let savedObjectsClientInstance: any; - let callWithInternalUser: any; - let internalRepository: any; - - beforeEach(() => { - savedObjectsClientInstance = { create: jest.fn() }; - callWithInternalUser = jest.fn(); - internalRepository = jest.fn(); - elasticsearchPlugin = { - getCluster: jest.fn(() => ({ callWithInternalUser })), - }; - savedObjects = { - SavedObjectsClient: jest.fn(() => savedObjectsClientInstance), - getSavedObjectsRepository: jest.fn(() => internalRepository), - }; - }); - - it('should return a SavedObjectsClient initialized with the saved objects internal repository', () => { - const result = getSavedObjectsClient(elasticsearchPlugin, savedObjects); - - expect(result).toBe(savedObjectsClientInstance); - expect(savedObjects.SavedObjectsClient).toHaveBeenCalledWith(internalRepository); + it('should call internalRepository create with overwrite: true', () => { + storeMlTelemetry(internalRepository, mlTelemetry); + expect(internalRepository.create.mock.calls[0][2].overwrite).toBe(true); }); }); describe('incrementFileDataVisualizerIndexCreationCount', () => { - let elasticsearchPlugin: any; let savedObjects: any; - let savedObjectsClientInstance: any; - let callWithInternalUser: any; let internalRepository: any; - function createSavedObjectsClientInstance( + function createInternalRepositoryInstance( telemetryEnabled?: boolean, indexCreationCount?: number ) { @@ -136,51 +93,42 @@ describe('ml_telemetry', () => { } function mockInit(telemetryEnabled?: boolean, indexCreationCount?: number): void { - savedObjectsClientInstance = createSavedObjectsClientInstance( - telemetryEnabled, - indexCreationCount - ); - callWithInternalUser = jest.fn(); - internalRepository = jest.fn(); + internalRepository = createInternalRepositoryInstance(telemetryEnabled, indexCreationCount); savedObjects = { - SavedObjectsClient: jest.fn(() => savedObjectsClientInstance), - getSavedObjectsRepository: jest.fn(() => internalRepository), - }; - elasticsearchPlugin = { - getCluster: jest.fn(() => ({ callWithInternalUser })), + createInternalRepository: jest.fn(() => internalRepository), }; } it('should not increment if telemetry status cannot be determined', async () => { mockInit(); - await incrementFileDataVisualizerIndexCreationCount(elasticsearchPlugin, savedObjects); + await incrementFileDataVisualizerIndexCreationCount(savedObjects); - expect(savedObjectsClientInstance.create.mock.calls).toHaveLength(0); + expect(internalRepository.create.mock.calls).toHaveLength(0); }); it('should not increment if telemetry status is disabled', async () => { mockInit(false); - await incrementFileDataVisualizerIndexCreationCount(elasticsearchPlugin, savedObjects); + await incrementFileDataVisualizerIndexCreationCount(savedObjects); - expect(savedObjectsClientInstance.create.mock.calls).toHaveLength(0); + expect(internalRepository.create.mock.calls).toHaveLength(0); }); it('should initialize index_creation_count with 1', async () => { mockInit(true); - await incrementFileDataVisualizerIndexCreationCount(elasticsearchPlugin, savedObjects); + await incrementFileDataVisualizerIndexCreationCount(savedObjects); - expect(savedObjectsClientInstance.create.mock.calls[0][0]).toBe('ml-telemetry'); - expect(savedObjectsClientInstance.create.mock.calls[0][1]).toEqual({ + expect(internalRepository.create.mock.calls[0][0]).toBe('ml-telemetry'); + expect(internalRepository.create.mock.calls[0][1]).toEqual({ file_data_visualizer: { index_creation_count: 1 }, }); }); it('should increment index_creation_count to 2', async () => { mockInit(true, 1); - await incrementFileDataVisualizerIndexCreationCount(elasticsearchPlugin, savedObjects); + await incrementFileDataVisualizerIndexCreationCount(savedObjects); - expect(savedObjectsClientInstance.create.mock.calls[0][0]).toBe('ml-telemetry'); - expect(savedObjectsClientInstance.create.mock.calls[0][1]).toEqual({ + expect(internalRepository.create.mock.calls[0][0]).toBe('ml-telemetry'); + expect(internalRepository.create.mock.calls[0][1]).toEqual({ file_data_visualizer: { index_creation_count: 2 }, }); }); diff --git a/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/ml_telemetry.ts b/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/ml_telemetry.ts index 1bac3f1780644..d76b1ee94e21e 100644 --- a/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/ml_telemetry.ts +++ b/x-pack/legacy/plugins/ml/server/lib/ml_telemetry/ml_telemetry.ts @@ -4,11 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; -import { SavedObjectsLegacyService } from 'src/legacy/server/kbn_server'; -import { callWithInternalUserFactory } from '../../client/call_with_internal_user_factory'; +import { + SavedObjectAttributes, + SavedObjectsServiceStart, + ISavedObjectsRepository, +} from 'src/core/server'; -export interface MlTelemetry { +export interface MlTelemetry extends SavedObjectAttributes { file_data_visualizer: { index_creation_count: number; }; @@ -29,35 +31,22 @@ export function createMlTelemetry(count: number = 0): MlTelemetry { } // savedObjects export function storeMlTelemetry( - elasticsearchPlugin: ElasticsearchPlugin, - savedObjects: SavedObjectsLegacyService, + internalRepository: ISavedObjectsRepository, mlTelemetry: MlTelemetry ): void { - const savedObjectsClient = getSavedObjectsClient(elasticsearchPlugin, savedObjects); - savedObjectsClient.create('ml-telemetry', mlTelemetry, { + internalRepository.create('ml-telemetry', mlTelemetry, { id: ML_TELEMETRY_DOC_ID, overwrite: true, }); } -// needs savedObjects and elasticsearchPlugin -export function getSavedObjectsClient( - elasticsearchPlugin: ElasticsearchPlugin, - savedObjects: SavedObjectsLegacyService -): any { - const { SavedObjectsClient, getSavedObjectsRepository } = savedObjects; - const callWithInternalUser = callWithInternalUserFactory(elasticsearchPlugin); - const internalRepository = getSavedObjectsRepository(callWithInternalUser); - return new SavedObjectsClient(internalRepository); -} export async function incrementFileDataVisualizerIndexCreationCount( - elasticsearchPlugin: ElasticsearchPlugin, - savedObjects: SavedObjectsLegacyService + savedObjects: SavedObjectsServiceStart ): Promise { - const savedObjectsClient = getSavedObjectsClient(elasticsearchPlugin, savedObjects); - + const internalRepository = await savedObjects.createInternalRepository(); try { - const { attributes } = await savedObjectsClient.get('telemetry', 'telemetry'); + const { attributes } = await internalRepository.get('telemetry', 'telemetry'); + if (attributes.enabled === false) { return; } @@ -70,7 +59,7 @@ export async function incrementFileDataVisualizerIndexCreationCount( let indicesCount = 1; try { - const { attributes } = (await savedObjectsClient.get( + const { attributes } = (await internalRepository.get( 'ml-telemetry', ML_TELEMETRY_DOC_ID )) as MlTelemetrySavedObject; @@ -80,5 +69,5 @@ export async function incrementFileDataVisualizerIndexCreationCount( } const mlTelemetry = createMlTelemetry(indicesCount); - storeMlTelemetry(elasticsearchPlugin, savedObjects, mlTelemetry); + storeMlTelemetry(internalRepository, mlTelemetry); } diff --git a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts index 10961182be841..43c276ac63a13 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts @@ -14,6 +14,7 @@ import { CoreSetup, IRouter, IScopedClusterClient, + SavedObjectsServiceStart, } from 'src/core/server'; import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; @@ -28,12 +29,10 @@ import { LICENSE_TYPE } from '../../common/constants/license'; import { annotationRoutes } from '../routes/annotations'; import { jobRoutes } from '../routes/anomaly_detectors'; import { dataFeedRoutes } from '../routes/datafeeds'; -// @ts-ignore: could not find declaration file for module import { indicesRoutes } from '../routes/indices'; import { jobValidationRoutes } from '../routes/job_validation'; import { makeMlUsageCollector } from '../lib/ml_telemetry'; import { notificationRoutes } from '../routes/notification_settings'; -// @ts-ignore: could not find declaration file for module import { systemRoutes } from '../routes/system'; import { dataFrameAnalyticsRoutes } from '../routes/data_frame_analytics'; import { dataRecognizer } from '../routes/modules'; @@ -45,7 +44,6 @@ import { filtersRoutes } from '../routes/filters'; import { resultsServiceRoutes } from '../routes/results_service'; import { jobServiceRoutes } from '../routes/job_service'; import { jobAuditMessagesRoutes } from '../routes/job_audit_messages'; -// @ts-ignore: could not find declaration file for module import { fileDataVisualizerRoutes } from '../routes/file_data_visualizer'; import { initMlServerLog, LogInitialization } from '../client/log'; import { HomeServerPluginSetup } from '../../../../../../src/plugins/home/server'; @@ -67,6 +65,7 @@ export interface MlCoreSetup { injectUiAppVars: (id: string, callback: () => {}) => any; http: MlHttpServiceSetup; savedObjects: SavedObjectsLegacyService; + coreSavedObjects: SavedObjectsServiceStart; elasticsearch: ElasticsearchServiceSetup; } export interface MlInitializerContext extends PluginInitializerContext { @@ -93,15 +92,11 @@ export interface RouteInitialization { route(route: ServerRoute | ServerRoute[]): void; router: IRouter; xpackMainPlugin: MlXpackMainPlugin; - savedObjects?: SavedObjectsLegacyService; + savedObjects?: SavedObjectsServiceStart; spacesPlugin: any; securityPlugin: any; cloud?: CloudSetup; } -export interface UsageInitialization { - elasticsearchPlugin: ElasticsearchPlugin; - savedObjects: SavedObjectsLegacyService; -} declare module 'kibana/server' { interface RequestHandlerContext { @@ -123,7 +118,7 @@ export class Plugin { public setup(core: MlCoreSetup, plugins: PluginsSetup) { const xpackMainPlugin: MlXpackMainPlugin = plugins.xpackMain; - const { http } = core; + const { http, coreSavedObjects } = core; const pluginId = this.pluginId; mirrorPluginStatus(xpackMainPlugin, plugins.ml); @@ -208,14 +203,10 @@ export class Plugin { const extendedRouteInitializationDeps: RouteInitialization = { ...routeInitializationDeps, config: this.config, - savedObjects: core.savedObjects, + savedObjects: coreSavedObjects, spacesPlugin: plugins.spaces, cloud: plugins.cloud, }; - const usageInitializationDeps: UsageInitialization = { - elasticsearchPlugin: plugins.elasticsearch, - savedObjects: core.savedObjects, - }; const logInitializationDeps: LogInitialization = { log: this.log, @@ -240,7 +231,7 @@ export class Plugin { fileDataVisualizerRoutes(extendedRouteInitializationDeps); initMlServerLog(logInitializationDeps); - makeMlUsageCollector(plugins.usageCollection, usageInitializationDeps); + makeMlUsageCollector(plugins.usageCollection, coreSavedObjects); } public stop() {} diff --git a/x-pack/legacy/plugins/ml/server/routes/file_data_visualizer.ts b/x-pack/legacy/plugins/ml/server/routes/file_data_visualizer.ts index 95f2a9fe7298f..d5a992c933293 100644 --- a/x-pack/legacy/plugins/ml/server/routes/file_data_visualizer.ts +++ b/x-pack/legacy/plugins/ml/server/routes/file_data_visualizer.ts @@ -138,7 +138,7 @@ export function fileDataVisualizerRoutes({ // follow-up import calls to just add additional data will include the `id` of the created // index, we'll ignore those and don't increment the counter. if (id === undefined) { - await incrementFileDataVisualizerIndexCreationCount(elasticsearchPlugin, savedObjects!); + await incrementFileDataVisualizerIndexCreationCount(savedObjects!); } const result = await importData( diff --git a/x-pack/legacy/plugins/ml/server/routes/job_audit_messages.ts b/x-pack/legacy/plugins/ml/server/routes/job_audit_messages.ts index 7298312990005..76986b935b993 100644 --- a/x-pack/legacy/plugins/ml/server/routes/job_audit_messages.ts +++ b/x-pack/legacy/plugins/ml/server/routes/job_audit_messages.ts @@ -50,7 +50,7 @@ export function jobAuditMessagesRoutes({ xpackMainPlugin, router }: RouteInitial /** * @apiGroup JobAuditMessages * - * @api {get} /api/ml/results/anomalies_table_data Get all audit messages + * @api {get} /api/ml/job_audit_messages/messages Get all audit messages * @apiName GetAllJobAuditMessages * @apiDescription Returns all audit messages */ From c6f5fdd061d93ad0d67335a658449be92e24640c Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Mon, 24 Feb 2020 17:42:34 +0100 Subject: [PATCH 023/123] Advanced settings UI change to centralize save state (#53693) --- .../advanced_settings/public/_index.scss | 2 +- .../public/management_app/_index.scss | 3 + .../management_app/advanced_settings.scss | 40 +- .../management_app/advanced_settings.tsx | 16 +- .../management_app/components/_index.scss | 1 + .../field/__snapshots__/field.test.tsx.snap | 7069 ++++++++--------- .../components/field/field.test.tsx | 267 +- .../management_app/components/field/field.tsx | 545 +- .../management_app/components/field/index.ts | 2 +- .../form/__snapshots__/form.test.tsx.snap | 1228 ++- .../management_app/components/form/_form.scss | 13 + .../components/form/_index.scss | 1 + .../components/form/form.test.tsx | 114 +- .../management_app/components/form/form.tsx | 280 +- .../public/management_app/types.ts | 13 + .../telemetry_management_section.tsx | 54 +- test/functional/page_objects/settings_page.ts | 6 +- .../translations/translations/ja-JP.json | 11 - .../translations/translations/zh-CN.json | 10 - 19 files changed, 5086 insertions(+), 4589 deletions(-) create mode 100644 src/plugins/advanced_settings/public/management_app/_index.scss create mode 100644 src/plugins/advanced_settings/public/management_app/components/_index.scss create mode 100644 src/plugins/advanced_settings/public/management_app/components/form/_form.scss create mode 100644 src/plugins/advanced_settings/public/management_app/components/form/_index.scss diff --git a/src/plugins/advanced_settings/public/_index.scss b/src/plugins/advanced_settings/public/_index.scss index f3fe78bf6a9c0..d13c37bff32d0 100644 --- a/src/plugins/advanced_settings/public/_index.scss +++ b/src/plugins/advanced_settings/public/_index.scss @@ -17,4 +17,4 @@ * under the License. */ - @import './management_app/advanced_settings'; +@import './management_app/index'; diff --git a/src/plugins/advanced_settings/public/management_app/_index.scss b/src/plugins/advanced_settings/public/management_app/_index.scss new file mode 100644 index 0000000000000..aa1980692f7b7 --- /dev/null +++ b/src/plugins/advanced_settings/public/management_app/_index.scss @@ -0,0 +1,3 @@ +@import './advanced_settings'; + +@import './components/index'; diff --git a/src/plugins/advanced_settings/public/management_app/advanced_settings.scss b/src/plugins/advanced_settings/public/management_app/advanced_settings.scss index 79b6feccb6b7d..016edb2817da8 100644 --- a/src/plugins/advanced_settings/public/management_app/advanced_settings.scss +++ b/src/plugins/advanced_settings/public/management_app/advanced_settings.scss @@ -17,21 +17,27 @@ * under the License. */ -.mgtAdvancedSettings__field { + .mgtAdvancedSettings__field { + * { margin-top: $euiSize; } - &Wrapper { - width: 640px; - @include internetExplorerOnly() { - min-height: 1px; - } + padding-left: $euiSizeS; + margin-left: -$euiSizeS; + &--unsaved { + // Simulates a left side border without shifting content + box-shadow: -$euiSizeXS 0px $euiColorSecondary; } - - &Actions { - padding-top: $euiSizeM; + &--invalid { + // Simulates a left side border without shifting content + box-shadow: -$euiSizeXS 0px $euiColorDanger; + } + @include internetExplorerOnly() { + min-height: 1px; + } + &Row { + padding-left: $euiSizeS; } @include internetExplorerOnly { @@ -40,3 +46,19 @@ } } } + +.mgtAdvancedSettingsForm__unsavedCount { + @include euiBreakpoint('xs', 's') { + display: none; + } +} + +.mgtAdvancedSettingsForm__unsavedCountMessage{ + // Simulates a left side border without shifting content + box-shadow: -$euiSizeXS 0px $euiColorSecondary; + padding-left: $euiSizeS; +} + +.mgtAdvancedSettingsForm__button { + width: 100%; +} diff --git a/src/plugins/advanced_settings/public/management_app/advanced_settings.tsx b/src/plugins/advanced_settings/public/management_app/advanced_settings.tsx index 5057d072e3e41..39312c9340ff9 100644 --- a/src/plugins/advanced_settings/public/management_app/advanced_settings.tsx +++ b/src/plugins/advanced_settings/public/management_app/advanced_settings.tsx @@ -38,7 +38,7 @@ import { ComponentRegistry } from '../'; import { getAriaName, toEditableConfig, DEFAULT_CATEGORY } from './lib'; -import { FieldSetting, IQuery } from './types'; +import { FieldSetting, IQuery, SettingsChanges } from './types'; interface AdvancedSettingsProps { enableSaving: boolean; @@ -177,6 +177,13 @@ export class AdvancedSettingsComponent extends Component< }); }; + saveConfig = async (changes: SettingsChanges) => { + const arr = Object.entries(changes).map(([key, value]) => + this.props.uiSettings.set(key, value) + ); + return Promise.all(arr); + }; + render() { const { filteredSettings, query, footerQueryMatched } = this.state; const componentRegistry = this.props.componentRegistry; @@ -205,18 +212,19 @@ export class AdvancedSettingsComponent extends Component<
+
+ + } + fullWidth={true} + title={ +

+ Array test setting + +

+ } > - - -
- - } - title={ -

- Array test setting - -

- } - > - - - - - - - + + + `; exports[`Field for array setting should render as read only with help text if overridden 1`] = ` - - - -
+ description={ + +
+ + + - - - - - default_value - , - } - } - /> - - - - - } - title={ -

- Array test setting - -

- } - > - + default_value + , + } + } /> - - } - isInvalid={false} - label="array:test:setting" - labelType="label" + + + + + } + fullWidth={true} + title={ +

+ Array test setting + +

+ } +> + - - - - - - + + } + label="array:test:setting" + labelType="label" + > + +
+ `; exports[`Field for array setting should render custom setting icon if it is custom 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Array test setting + + } + type="asterisk" + /> +

+ } > - - -
- - } - title={ -

- Array test setting - - } - type="asterisk" - /> -

- } - > - - - - - - - + + + `; exports[`Field for array setting should render default value if there is no user value set 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Array test setting + +

+ } > - - -
- - } - title={ -

- Array test setting - -

- } - > - + + +`; + +exports[`Field for array setting should render unsaved value if there are unsaved changes 1`] = ` + +
+ + } + fullWidth={true} + title={ +

+ Array test setting + + } + type="asterisk" + /> +

+ } +> + + + +

- - - - - - + Setting is currently not saved. +

+
+
+ `; exports[`Field for array setting should render user value if there is user value is set 1`] = ` - - - -
+ description={ + +
+ + + - + default_value + , + } + } /> - - - - default_value - , - } - } - /> - - - - } - title={ -

- Array test setting - -

- } - > - - - - - -     - - - } - isInvalid={false} - label="array:test:setting" - labelType="label" - > - - - - - - + + + + } + fullWidth={true} + title={ +

+ Array test setting + +

+ } +> + + + + + +     + + + } + label="array:test:setting" + labelType="label" + > + + + `; exports[`Field for boolean setting should render as read only if saving is disabled 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Boolean test setting + +

+ } > - - -
- - } - title={ -

- Boolean test setting - -

- } - > - - - } - onChange={[Function]} - onKeyDown={[Function]} + - - - - - + } + onChange={[Function]} + /> + + `; exports[`Field for boolean setting should render as read only with help text if overridden 1`] = ` - - - -
+ description={ + +
+ + + - - - - - true - , - } - } - /> - - - - - } - title={ -

- Boolean test setting - -

- } - > - + true + , + } + } /> - - } - isInvalid={false} - label="boolean:test:setting" - labelType="label" + + + + + } + fullWidth={true} + title={ +

+ Boolean test setting + +

+ } +> + - - } - onChange={[Function]} - onKeyDown={[Function]} + + + } + label="boolean:test:setting" + labelType="label" + > + - - - - - + } + onChange={[Function]} + /> +
+ `; exports[`Field for boolean setting should render custom setting icon if it is custom 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Boolean test setting + + } + type="asterisk" + /> +

+ } > - - -
- - } - title={ -

- Boolean test setting - - } - type="asterisk" - /> -

- } - > - - - } - onChange={[Function]} - onKeyDown={[Function]} + - - - - - + } + onChange={[Function]} + /> + + `; exports[`Field for boolean setting should render default value if there is no user value set 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Boolean test setting + +

+ } > - - -
- - } - title={ -

- Boolean test setting - -

+ } - > - - + onChange={[Function]} + /> + + +`; + +exports[`Field for boolean setting should render unsaved value if there are unsaved changes 1`] = ` + +
+ + } + fullWidth={true} + title={ +

+ Boolean test setting + + } + type="asterisk" + /> +

+ } +> + + - - - - - + } + onChange={[Function]} + /> + +

+ Setting is currently not saved. +

+
+ + `; exports[`Field for boolean setting should render user value if there is user value is set 1`] = ` - - - -
+ description={ + +
+ + + - + true + , + } + } /> - - - - true - , - } - } - /> - - - - } - title={ -

- Boolean test setting - -

- } - > - - - - - -     - - - } - isInvalid={false} - label="boolean:test:setting" - labelType="label" - > - + + + } + fullWidth={true} + title={ +

+ Boolean test setting + +

+ } +> + + + - } - onChange={[Function]} - onKeyDown={[Function]} + +     + + + } + label="boolean:test:setting" + labelType="label" + > + - - - - - + } + onChange={[Function]} + /> +
+ `; exports[`Field for image setting should render as read only if saving is disabled 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Image test setting + +

+ } > - - -
- - } - title={ -

- Image test setting - -

- } - > - - - - - - - + + + `; exports[`Field for image setting should render as read only with help text if overridden 1`] = ` - - - -
+ description={ + +
+ + + - - - - - null - , - } - } - /> - - - - - } - title={ -

- Image test setting - -

- } - > - + null + , + } + } /> - - } - isInvalid={false} - label="image:test:setting" - labelType="label" + + + + + } + fullWidth={true} + title={ +

+ Image test setting + +

+ } +> + - - - - - - + + } + label="image:test:setting" + labelType="label" + > + +
+ `; exports[`Field for image setting should render custom setting icon if it is custom 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Image test setting + + } + type="asterisk" + /> +

+ } > - - -
- - } - title={ -

- Image test setting - - } - type="asterisk" - /> -

- } - > - - - - - - - + + + `; exports[`Field for image setting should render default value if there is no user value set 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Image test setting + +

+ } > - - -
- - } - title={ -

- Image test setting - -

- } - > - + + +`; + +exports[`Field for image setting should render unsaved value if there are unsaved changes 1`] = ` + +
+ + } + fullWidth={true} + title={ +

+ Image test setting + + } + type="asterisk" + /> +

+ } +> + + + +

- - - - - - + Setting is currently not saved. +

+
+
+ `; exports[`Field for image setting should render user value if there is user value is set 1`] = ` - - - -
+ description={ + +
+ + + - + null + , + } + } /> - - - - null - , - } - } - /> - - - - } - title={ -

- Image test setting - -

- } - > - - - - - -     - - - - - - - - } - isInvalid={false} - label="image:test:setting" - labelType="label" - > - - - - - - + + + + } + fullWidth={true} + title={ +

+ Image test setting + +

+ } +> + + + + + +     + + + + + + + + } + label="image:test:setting" + labelType="label" + > + + + `; exports[`Field for json setting should render as read only if saving is disabled 1`] = ` - - - -
+ description={ + +
+ + + - + {} + , + } + } /> - - - - {} - , - } - } - /> - - - - } - title={ -

- Json test setting - -

- } + + + + } + fullWidth={true} + title={ +

+ Json test setting + +

+ } +> + +
- -
- -
-
- - - - + +
+
+ `; exports[`Field for json setting should render as read only with help text if overridden 1`] = ` - - - -
+ description={ + +
+ + + - + {} + , + } + } /> - - - - {} - , - } - } - /> - - - - } - title={ -

- Json test setting - -

- } + + + + } + fullWidth={true} + title={ +

+ Json test setting + +

+ } +> + + + + } + label="json:test:setting" + labelType="label" + > +
- - - + -
- -
-
- - - - + fullWidth={true} + height="auto" + isReadOnly={true} + maxLines={30} + minLines={6} + mode="json" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="{\\"hello\\": \\"world\\"}" + width="100%" + /> +
+
+ `; exports[`Field for json setting should render custom setting icon if it is custom 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Json test setting + + } + type="asterisk" + /> +

+ } > - - -
- - } - title={ -

- Json test setting - - } - type="asterisk" - /> -

- } +
- -
- -
-
- - - - + +
+ + `; exports[`Field for json setting should render default value if there is no user value set 1`] = ` - - - -
+ description={ + +
+ + + - + {} + , + } + } /> - - - - {} - , - } - } - /> - - - - } - title={ -

- Json test setting - -

- } + + + + } + fullWidth={true} + title={ +

+ Json test setting + +

+ } +> + + + + + +     + + + } + label="json:test:setting" + labelType="label" + > +
- - - - - -     - - - } - isInvalid={false} - label="json:test:setting" - labelType="label" + +
+
+ +`; + +exports[`Field for json setting should render unsaved value if there are unsaved changes 1`] = ` + +
+ + } + fullWidth={true} + title={ +

+ Json test setting + + } + type="asterisk" + /> +

+ } +> + +
+ +
+ +

-

- -
-
- - - - + Setting is currently not saved. +

+ + + `; exports[`Field for json setting should render user value if there is user value is set 1`] = ` - - - -
+ description={ + +
+ + + - + {} + , + } + } /> - - - - {} - , - } - } - /> - - - - } - title={ -

- Json test setting - -

- } + + + + } + fullWidth={true} + title={ +

+ Json test setting + +

+ } +> + + + + + +     + + + } + label="json:test:setting" + labelType="label" + > +
- - - - - -     - - - } - isInvalid={false} - label="json:test:setting" - labelType="label" - > -
- -
-
- - - - + +
+
+ `; exports[`Field for markdown setting should render as read only if saving is disabled 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Markdown test setting + +

+ } > - - -
- - } - title={ -

- Markdown test setting - -

- } +
- -
- -
-
- - - - + +
+ + `; exports[`Field for markdown setting should render as read only with help text if overridden 1`] = ` - - - -
+ description={ + +
+ + + - + null + , + } + } /> - - - - null - , - } - } - /> - - - - } - title={ -

- Markdown test setting - -

- } + + + + } + fullWidth={true} + title={ +

+ Markdown test setting + +

+ } +> + + + + } + label="markdown:test:setting" + labelType="label" + > +
- - - + -
- -
-
- - - - + fullWidth={true} + height="auto" + isReadOnly={true} + maxLines={30} + minLines={6} + mode="markdown" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="**bold**" + width="100%" + /> +
+
+ `; exports[`Field for markdown setting should render custom setting icon if it is custom 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Markdown test setting + + } + type="asterisk" + /> +

+ } > - - -
- - } - title={ -

- Markdown test setting - - } - type="asterisk" - /> -

- } +
- -
- -
-
- - - - + +
+ + `; exports[`Field for markdown setting should render default value if there is no user value set 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Markdown test setting + +

+ } > - - -
- - } - title={ -

- Markdown test setting - -

- } +
+ +
+ + +`; + +exports[`Field for markdown setting should render unsaved value if there are unsaved changes 1`] = ` + +
+ + } + fullWidth={true} + title={ +

+ Markdown test setting + + } + type="asterisk" + /> +

+ } +> + +
- +
+ +

-

- -
-
- - - - + Setting is currently not saved. +

+ + + `; exports[`Field for markdown setting should render user value if there is user value is set 1`] = ` - - - -
+ description={ + +
+ + + - + null + , + } + } /> - - - - null - , - } - } - /> - - - - } - title={ -

- Markdown test setting - -

- } + + + + } + fullWidth={true} + title={ +

+ Markdown test setting + +

+ } +> + + + + + +     + + + } + label="markdown:test:setting" + labelType="label" + > +
- - - - - -     - - - } - isInvalid={false} - label="markdown:test:setting" - labelType="label" - > -
- -
-
- - - - + +
+
+ `; exports[`Field for number setting should render as read only if saving is disabled 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Number test setting + +

+ } > - - -
- - } - title={ -

- Number test setting - -

- } - > - - - - - - - + + + `; exports[`Field for number setting should render as read only with help text if overridden 1`] = ` - - - -
+ description={ + +
+ + + - - - - - 5 - , - } - } - /> - - - - - } - title={ -

- Number test setting - -

- } - > - + 5 + , + } + } /> - - } - isInvalid={false} - label="number:test:setting" - labelType="label" + + + + + } + fullWidth={true} + title={ +

+ Number test setting + +

+ } +> + - - - - - - + + } + label="number:test:setting" + labelType="label" + > + +
+ `; exports[`Field for number setting should render custom setting icon if it is custom 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Number test setting + + } + type="asterisk" + /> +

+ } > - - -
- - } - title={ -

- Number test setting - - } - type="asterisk" - /> -

- } - > - - - - - - - + + + +`; + +exports[`Field for number setting should render default value if there is no user value set 1`] = ` + +
+ + } + fullWidth={true} + title={ +

+ Number test setting + +

+ } +> + + + + `; -exports[`Field for number setting should render default value if there is no user value set 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Number test setting + + } + type="asterisk" + /> +

+ } > - - -
- - } - title={ -

- Number test setting - -

- } - > - + +

- - - - - - + Setting is currently not saved. +

+
+
+ `; exports[`Field for number setting should render user value if there is user value is set 1`] = ` - - - -
+ description={ + +
+ + + - + 5 + , + } + } /> - - - - 5 - , - } - } - /> - - - - } - title={ -

- Number test setting - -

- } - > - - - - - -     - - - } - isInvalid={false} - label="number:test:setting" - labelType="label" - > - - - - - - + + + + } + fullWidth={true} + title={ +

+ Number test setting + +

+ } +> + + + + + +     + + + } + label="number:test:setting" + labelType="label" + > + + + `; exports[`Field for select setting should render as read only if saving is disabled 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Select test setting + +

+ } > - - -
- - } - title={ -

- Select test setting - -

- } - > - - - - - - - + + + `; exports[`Field for select setting should render as read only with help text if overridden 1`] = ` - - - -
+ description={ + +
+ + + - - - - - Orange - , - } - } - /> - - - - - } - title={ -

- Select test setting - -

- } - > - + Orange + , + } + } /> - - } - isInvalid={false} - label="select:test:setting" - labelType="label" + + + + + } + fullWidth={true} + title={ +

+ Select test setting + +

+ } +> + - - - - - - + + } + label="select:test:setting" + labelType="label" + > + +
+ `; exports[`Field for select setting should render custom setting icon if it is custom 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Select test setting + + } + type="asterisk" + /> +

+ } > - - -
- - } - title={ -

- Select test setting - - } - type="asterisk" - /> -

- } - > - - - - - - - + + + `; exports[`Field for select setting should render default value if there is no user value set 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ Select test setting + +

+ } > - - -
- - } - title={ -

- Select test setting - -

- } - > - + + +`; + +exports[`Field for select setting should render unsaved value if there are unsaved changes 1`] = ` + +
+ + } + fullWidth={true} + title={ +

+ Select test setting + + } + type="asterisk" + /> +

+ } +> + + + +

- - - - - - + Setting is currently not saved. +

+
+
+ `; exports[`Field for select setting should render user value if there is user value is set 1`] = ` - - - -
+ description={ + +
+ + + - + Orange + , + } + } /> - - - - Orange - , - } - } - /> - - - - } - title={ -

- Select test setting - -

- } - > - - - - - -     - - - } - isInvalid={false} - label="select:test:setting" - labelType="label" - > - - - - - - + + + + } + fullWidth={true} + title={ +

+ Select test setting + +

+ } +> + + + + + +     + + + } + label="select:test:setting" + labelType="label" + > + + + `; exports[`Field for string setting should render as read only if saving is disabled 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ String test setting + +

+ } > - - -
- - } - title={ -

- String test setting - -

- } - > - - - - - - - + + + `; exports[`Field for string setting should render as read only with help text if overridden 1`] = ` - - - -
+ description={ + +
+ + + - - - - - null - , - } - } - /> - - - - - } - title={ -

- String test setting - -

- } - > - + null + , + } + } /> - - } - isInvalid={false} - label="string:test:setting" - labelType="label" + + + + + } + fullWidth={true} + title={ +

+ String test setting + +

+ } +> + - - - - - - + + } + label="string:test:setting" + labelType="label" + > + +
+ `; exports[`Field for string setting should render custom setting icon if it is custom 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ String test setting + + } + type="asterisk" + /> +

+ } > - - -
- - } - title={ -

- String test setting - - } - type="asterisk" - /> -

- } - > - - - - - - - + + + `; exports[`Field for string setting should render default value if there is no user value set 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ String test setting + +

+ } > - - -
- - } - title={ -

- String test setting - -

- } - > - + + +`; + +exports[`Field for string setting should render unsaved value if there are unsaved changes 1`] = ` + +
+ + } + fullWidth={true} + title={ +

+ String test setting + + } + type="asterisk" + /> +

+ } +> + + + +

- - - - - - + Setting is currently not saved. +

+
+
+ `; exports[`Field for string setting should render user value if there is user value is set 1`] = ` - - - -
+ description={ + +
+ + + - + null + , + } + } /> - - - - null - , - } - } - /> - - - - } - title={ -

- String test setting - -

- } - > - - - - - -     - - - } - isInvalid={false} - label="string:test:setting" - labelType="label" - > - - - - - - + + + + } + fullWidth={true} + title={ +

+ String test setting + +

+ } +> + + + + + +     + + + } + label="string:test:setting" + labelType="label" + > + + + `; exports[`Field for stringWithValidation setting should render as read only if saving is disabled 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ String test validation setting + +

+ } > - - -
- - } - title={ -

- String test validation setting - -

- } - > - - - - - - - + + + `; exports[`Field for stringWithValidation setting should render as read only with help text if overridden 1`] = ` - - - -
+ description={ + +
+ + + - - - - - foo-default - , - } - } - /> - - - - - } - title={ -

- String test validation setting - -

- } - > - + foo-default + , + } + } /> - - } - isInvalid={false} - label="string:test-validation:setting" - labelType="label" + + + + + } + fullWidth={true} + title={ +

+ String test validation setting + +

+ } +> + - - - - - - + + } + label="string:test-validation:setting" + labelType="label" + > + +
+ `; exports[`Field for stringWithValidation setting should render custom setting icon if it is custom 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ String test validation setting + + } + type="asterisk" + /> +

+ } > - - -
- - } - title={ -

- String test validation setting - - } - type="asterisk" - /> -

- } - > - - - - - - - + + + `; exports[`Field for stringWithValidation setting should render default value if there is no user value set 1`] = ` - +
+ + } + fullWidth={true} + title={ +

+ String test validation setting + +

+ } > - - -
- - } - title={ -

- String test validation setting - -

- } - > - + + +`; + +exports[`Field for stringWithValidation setting should render unsaved value if there are unsaved changes 1`] = ` + +
+ + } + fullWidth={true} + title={ +

+ String test validation setting + + } + type="asterisk" + /> +

+ } +> + + + +

- - - - - - + Setting is currently not saved. +

+
+
+ `; exports[`Field for stringWithValidation setting should render user value if there is user value is set 1`] = ` - - - -
+ description={ + +
+ + + - + foo-default + , + } + } /> - - - - foo-default - , - } - } - /> - - - - } - title={ -

- String test validation setting - -

- } - > - - - - - -     - - - } - isInvalid={false} - label="string:test-validation:setting" - labelType="label" - > - - - - - - + + + + } + fullWidth={true} + title={ +

+ String test validation setting + +

+ } +> + + + + + +     + + + } + label="string:test-validation:setting" + labelType="label" + > + + + `; diff --git a/src/plugins/advanced_settings/public/management_app/components/field/field.test.tsx b/src/plugins/advanced_settings/public/management_app/components/field/field.test.tsx index 81df22ccf6e43..8e41fed685898 100644 --- a/src/plugins/advanced_settings/public/management_app/components/field/field.test.tsx +++ b/src/plugins/advanced_settings/public/management_app/components/field/field.test.tsx @@ -20,21 +20,14 @@ import React from 'react'; import { I18nProvider } from '@kbn/i18n/react'; import { shallowWithI18nProvider, mountWithI18nProvider } from 'test_utils/enzyme_helpers'; -import { mount } from 'enzyme'; +import { mount, ReactWrapper } from 'enzyme'; import { FieldSetting } from '../../types'; import { UiSettingsType, StringValidation } from '../../../../../../core/public'; import { notificationServiceMock, docLinksServiceMock } from '../../../../../../core/public/mocks'; // @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; -import { Field } from './field'; - -jest.mock('ui/notify', () => ({ - toastNotifications: { - addDanger: () => {}, - add: jest.fn(), - }, -})); +import { Field, getEditableValue } from './field'; jest.mock('brace/theme/textmate', () => 'brace/theme/textmate'); jest.mock('brace/mode/markdown', () => 'brace/mode/markdown'); @@ -45,6 +38,18 @@ const defaults = { category: ['category'], }; +const exampleValues = { + array: ['example_value'], + boolean: false, + image: 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=', + json: { foo: 'bar2' }, + markdown: 'Hello World', + number: 1, + select: 'banana', + string: 'hello world', + stringWithValidation: 'foo', +}; + const settings: Record = { array: { name: 'array:test:setting', @@ -161,7 +166,7 @@ const settings: Record = { description: 'Description for String test validation setting', type: 'string', validation: { - regex: new RegExp('/^foo'), + regex: new RegExp('^foo'), message: 'must start with "foo"', }, value: undefined, @@ -182,11 +187,22 @@ const userValues = { string: 'foo', stringWithValidation: 'fooUserValue', }; + const invalidUserValues = { stringWithValidation: 'invalidUserValue', }; -const save = jest.fn(() => Promise.resolve(true)); -const clear = jest.fn(() => Promise.resolve(true)); + +const handleChange = jest.fn(); +const clearChange = jest.fn(); + +const getFieldSettingValue = (wrapper: ReactWrapper, name: string, type: string) => { + const field = findTestSubject(wrapper, `advancedSetting-editField-${name}`); + if (type === 'boolean') { + return field.props()['aria-checked']; + } else { + return field.props().value; + } +}; describe('Field', () => { Object.keys(settings).forEach(type => { @@ -197,8 +213,7 @@ describe('Field', () => { const component = shallowWithI18nProvider( { value: userValues[type], isOverridden: true, }} - save={save} - clear={clear} + handleChange={handleChange} enableSaving={true} toasts={notificationServiceMock.createStartContract().toasts} dockLinks={docLinksServiceMock.createStartContract().links} @@ -232,14 +246,12 @@ describe('Field', () => { const component = shallowWithI18nProvider( ); - expect(component).toMatchSnapshot(); }); @@ -251,8 +263,7 @@ describe('Field', () => { // @ts-ignore value: userValues[type], }} - save={save} - clear={clear} + handleChange={handleChange} enableSaving={true} toasts={notificationServiceMock.createStartContract().toasts} dockLinks={docLinksServiceMock.createStartContract().links} @@ -269,48 +280,44 @@ describe('Field', () => { ...setting, isCustom: true, }} - save={save} - clear={clear} + handleChange={handleChange} enableSaving={true} toasts={notificationServiceMock.createStartContract().toasts} dockLinks={docLinksServiceMock.createStartContract().links} /> ); - expect(component).toMatchSnapshot(); }); - }); - - if (type === 'select') { - it('should use options for rendering values', () => { - const component = mountWithI18nProvider( + it('should render unsaved value if there are unsaved changes', async () => { + const component = shallowWithI18nProvider( ); - const select = findTestSubject(component, `advancedSetting-editField-${setting.name}`); - // @ts-ignore - const labels = select.find('option').map(option => option.prop('value')); - expect(labels).toEqual(['apple', 'orange', 'banana']); + expect(component).toMatchSnapshot(); }); + }); - it('should use optionLabels for rendering labels', () => { + if (type === 'select') { + it('should use options for rendering values and optionsLabels for rendering labels', () => { const component = mountWithI18nProvider( { ); const select = findTestSubject(component, `advancedSetting-editField-${setting.name}`); // @ts-ignore + const values = select.find('option').map(option => option.prop('value')); + expect(values).toEqual(['apple', 'orange', 'banana']); + // @ts-ignore const labels = select.find('option').map(option => option.text()); expect(labels).toEqual(['Apple', 'Orange', 'banana']); }); @@ -328,8 +338,8 @@ describe('Field', () => { { const userValue = userValues[type]; (component.instance() as Field).getImageAsBase64 = ({}: Blob) => Promise.resolve(''); - it('should be able to change value from no value and cancel', async () => { - await (component.instance() as Field).onImageChange([userValue]); - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-cancelEditField-${setting.name}`).simulate( - 'click' - ); - expect( - (component.instance() as Field).state.unsavedValue === - (component.instance() as Field).state.savedValue - ).toBe(true); - }); - - it('should be able to change value and save', async () => { - await (component.instance() as Field).onImageChange([userValue]); - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-saveEditField-${setting.name}`).simulate( - 'click' - ); - expect(save).toBeCalled(); - component.setState({ savedValue: userValue }); + it('should be able to change value and cancel', async () => { + (component.instance() as Field).onImageChange([userValue]); + expect(handleChange).toBeCalled(); await wrapper.setProps({ + unsavedChanges: { + value: userValue, + changeImage: true, + }, setting: { ...(component.instance() as Field).props.setting, value: userValue, }, }); - await (component.instance() as Field).cancelChangeImage(); + expect(clearChange).toBeCalledWith(setting.name); wrapper.update(); }); - it('should be able to change value from existing value and save', async () => { + it('should be able to change value from existing value', async () => { + await wrapper.setProps({ + unsavedChanges: {}, + }); const updated = wrapper.update(); findTestSubject(updated, `advancedSetting-changeImage-${setting.name}`).simulate('click'); - const newUserValue = `${userValue}=`; await (component.instance() as Field).onImageChange([newUserValue]); - const updated2 = wrapper.update(); - findTestSubject(updated2, `advancedSetting-saveEditField-${setting.name}`).simulate( - 'click' - ); - expect(save).toBeCalled(); - component.setState({ savedValue: newUserValue }); - await wrapper.setProps({ - setting: { - ...(component.instance() as Field).props.setting, - value: newUserValue, - }, - }); - wrapper.update(); + expect(handleChange).toBeCalled(); }); it('should be able to reset to default value', async () => { const updated = wrapper.update(); findTestSubject(updated, `advancedSetting-resetField-${setting.name}`).simulate('click'); - expect(clear).toBeCalled(); + expect(handleChange).toBeCalledWith(setting.name, { + value: getEditableValue(setting.type, setting.defVal), + changeImage: true, + }); }); }); } else if (type === 'markdown' || type === 'json') { describe(`for changing ${type} setting`, () => { const { wrapper, component } = setup(); const userValue = userValues[type]; - const fieldUserValue = userValue; - - it('should be able to change value and cancel', async () => { - (component.instance() as Field).onCodeEditorChange(fieldUserValue as UiSettingsType); - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-cancelEditField-${setting.name}`).simulate( - 'click' - ); - expect( - (component.instance() as Field).state.unsavedValue === - (component.instance() as Field).state.savedValue - ).toBe(true); - }); - it('should be able to change value and save', async () => { - (component.instance() as Field).onCodeEditorChange(fieldUserValue as UiSettingsType); - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-saveEditField-${setting.name}`).simulate( - 'click' - ); - expect(save).toBeCalled(); - component.setState({ savedValue: fieldUserValue }); + it('should be able to change value', async () => { + (component.instance() as Field).onCodeEditorChange(userValue as UiSettingsType); + expect(handleChange).toBeCalledWith(setting.name, { value: userValue }); await wrapper.setProps({ setting: { ...(component.instance() as Field).props.setting, @@ -445,19 +417,21 @@ describe('Field', () => { wrapper.update(); }); + it('should be able to reset to default value', async () => { + const updated = wrapper.update(); + findTestSubject(updated, `advancedSetting-resetField-${setting.name}`).simulate('click'); + expect(handleChange).toBeCalledWith(setting.name, { + value: getEditableValue(setting.type, setting.defVal), + }); + }); + if (type === 'json') { it('should be able to clear value and have empty object populate', async () => { - (component.instance() as Field).onCodeEditorChange('' as UiSettingsType); + await (component.instance() as Field).onCodeEditorChange('' as UiSettingsType); wrapper.update(); - expect((component.instance() as Field).state.unsavedValue).toEqual('{}'); + expect(handleChange).toBeCalledWith(setting.name, { value: setting.defVal }); }); } - - it('should be able to reset to default value', async () => { - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-resetField-${setting.name}`).simulate('click'); - expect(clear).toBeCalled(); - }); }); } else { describe(`for changing ${type} setting`, () => { @@ -470,76 +444,45 @@ describe('Field', () => { // @ts-ignore const invalidUserValue = invalidUserValues[type]; it('should display an error when validation fails', async () => { - (component.instance() as Field).onFieldChange(invalidUserValue); + await (component.instance() as Field).onFieldChange(invalidUserValue); + const expectedUnsavedChanges = { + value: invalidUserValue, + error: (setting.validation as StringValidation).message, + isInvalid: true, + }; + expect(handleChange).toBeCalledWith(setting.name, expectedUnsavedChanges); + wrapper.setProps({ unsavedChanges: expectedUnsavedChanges }); const updated = wrapper.update(); const errorMessage = updated.find('.euiFormErrorText').text(); - expect(errorMessage).toEqual((setting.validation as StringValidation).message); + expect(errorMessage).toEqual(expectedUnsavedChanges.error); }); } - it('should be able to change value and cancel', async () => { - (component.instance() as Field).onFieldChange(fieldUserValue); + it('should be able to change value', async () => { + await (component.instance() as Field).onFieldChange(fieldUserValue); const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-cancelEditField-${setting.name}`).simulate( - 'click' - ); - expect( - (component.instance() as Field).state.unsavedValue === - (component.instance() as Field).state.savedValue - ).toBe(true); + expect(handleChange).toBeCalledWith(setting.name, { value: fieldUserValue }); + updated.setProps({ unsavedChanges: { value: fieldUserValue } }); + const currentValue = getFieldSettingValue(updated, setting.name, type); + expect(currentValue).toEqual(fieldUserValue); }); - it('should be able to change value and save', async () => { - (component.instance() as Field).onFieldChange(fieldUserValue); - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-saveEditField-${setting.name}`).simulate( - 'click' - ); - expect(save).toBeCalled(); - component.setState({ savedValue: fieldUserValue }); + it('should be able to reset to default value', async () => { await wrapper.setProps({ - setting: { - ...(component.instance() as Field).props.setting, - value: userValue, - }, + unsavedChanges: {}, + setting: { ...setting, value: fieldUserValue }, }); - wrapper.update(); - }); - - it('should be able to reset to default value', async () => { const updated = wrapper.update(); findTestSubject(updated, `advancedSetting-resetField-${setting.name}`).simulate('click'); - expect(clear).toBeCalled(); + const expectedEditableValue = getEditableValue(setting.type, setting.defVal); + expect(handleChange).toBeCalledWith(setting.name, { + value: expectedEditableValue, + }); + updated.setProps({ unsavedChanges: { value: expectedEditableValue } }); + const currentValue = getFieldSettingValue(updated, setting.name, type); + expect(currentValue).toEqual(expectedEditableValue); }); }); } }); - - it('should show a reload toast when saving setting requiring a page reload', async () => { - const setting = { - ...settings.string, - requiresPageReload: true, - }; - const toasts = notificationServiceMock.createStartContract().toasts; - const wrapper = mountWithI18nProvider( - - ); - (wrapper.instance() as Field).onFieldChange({ target: { value: 'a new value' } }); - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-saveEditField-${setting.name}`).simulate('click'); - expect(save).toHaveBeenCalled(); - await save(); - expect(toasts.add).toHaveBeenCalledWith( - expect.objectContaining({ - title: expect.stringContaining('Please reload the page'), - }) - ); - }); }); diff --git a/src/plugins/advanced_settings/public/management_app/components/field/field.tsx b/src/plugins/advanced_settings/public/management_app/components/field/field.tsx index 7158e3d5e7b3e..d9c3752d1c0a5 100644 --- a/src/plugins/advanced_settings/public/management_app/components/field/field.tsx +++ b/src/plugins/advanced_settings/public/management_app/components/field/field.tsx @@ -18,17 +18,16 @@ */ import React, { PureComponent, Fragment } from 'react'; -import ReactDOM from 'react-dom'; +import classNames from 'classnames'; import 'brace/theme/textmate'; import 'brace/mode/markdown'; import { EuiBadge, - EuiButton, - EuiButtonEmpty, EuiCode, EuiCodeBlock, + EuiScreenReaderOnly, // @ts-ignore EuiCodeEditor, EuiDescribedFormGroup, @@ -36,23 +35,20 @@ import { EuiFieldText, // @ts-ignore EuiFilePicker, - EuiFlexGroup, - EuiFlexItem, EuiFormRow, EuiIconTip, EuiImage, EuiLink, EuiSpacer, - EuiToolTip, EuiText, EuiSelect, EuiSwitch, EuiSwitchEvent, - keyCodes, + EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { FieldSetting } from '../../types'; +import { FieldSetting, FieldState } from '../../types'; import { isDefaultValue } from '../../lib'; import { UiSettingsType, @@ -64,71 +60,37 @@ import { interface FieldProps { setting: FieldSetting; - save: (name: string, value: string) => Promise; - clear: (name: string) => Promise; + handleChange: (name: string, value: FieldState) => void; enableSaving: boolean; dockLinks: DocLinksStart['links']; toasts: ToastsStart; + clearChange?: (name: string) => void; + unsavedChanges?: FieldState; + loading?: boolean; } -interface FieldState { - unsavedValue: any; - savedValue: any; - loading: boolean; - isInvalid: boolean; - error: string | null; - changeImage: boolean; - isJsonArray: boolean; -} - -export class Field extends PureComponent { - private changeImageForm: EuiFilePicker | undefined; - constructor(props: FieldProps) { - super(props); - const { type, value, defVal } = this.props.setting; - const editableValue = this.getEditableValue(type, value, defVal); - - this.state = { - isInvalid: false, - error: null, - loading: false, - changeImage: false, - savedValue: editableValue, - unsavedValue: editableValue, - isJsonArray: type === 'json' ? Array.isArray(JSON.parse(String(defVal) || '{}')) : false, - }; - } - - UNSAFE_componentWillReceiveProps(nextProps: FieldProps) { - const { unsavedValue } = this.state; - const { type, value, defVal } = nextProps.setting; - const editableValue = this.getEditableValue(type, value, defVal); - - this.setState({ - savedValue: editableValue, - unsavedValue: value === null || value === undefined ? editableValue : unsavedValue, - }); +export const getEditableValue = ( + type: UiSettingsType, + value: FieldSetting['value'], + defVal?: FieldSetting['defVal'] +) => { + const val = value === null || value === undefined ? defVal : value; + switch (type) { + case 'array': + return (val as string[]).join(', '); + case 'boolean': + return !!val; + case 'number': + return Number(val); + case 'image': + return val; + default: + return val || ''; } +}; - getEditableValue( - type: UiSettingsType, - value: FieldSetting['value'], - defVal: FieldSetting['defVal'] - ) { - const val = value === null || value === undefined ? defVal : value; - switch (type) { - case 'array': - return (val as string[]).join(', '); - case 'boolean': - return !!val; - case 'number': - return Number(val); - case 'image': - return val; - default: - return val || ''; - } - } +export class Field extends PureComponent { + private changeImageForm: EuiFilePicker | undefined = React.createRef(); getDisplayedDefaultValue( type: UiSettingsType, @@ -150,47 +112,60 @@ export class Field extends PureComponent { } } - setLoading(loading: boolean) { - this.setState({ - loading, - }); - } + handleChange = (unsavedChanges: FieldState) => { + this.props.handleChange(this.props.setting.name, unsavedChanges); + }; - clearError() { - this.setState({ - isInvalid: false, - error: null, - }); + resetField = () => { + const { type, defVal } = this.props.setting; + if (type === 'image') { + this.cancelChangeImage(); + return this.handleChange({ + value: getEditableValue(type, defVal), + changeImage: true, + }); + } + return this.handleChange({ value: getEditableValue(type, defVal) }); + }; + + componentDidUpdate(prevProps: FieldProps) { + if ( + prevProps.setting.type === 'image' && + prevProps.unsavedChanges?.value && + !this.props.unsavedChanges?.value + ) { + this.cancelChangeImage(); + } } onCodeEditorChange = (value: UiSettingsType) => { - const { type } = this.props.setting; - const { isJsonArray } = this.state; + const { defVal, type } = this.props.setting; let newUnsavedValue; - let isInvalid = false; - let error = null; + let errorParams = {}; switch (type) { case 'json': + const isJsonArray = Array.isArray(JSON.parse((defVal as string) || '{}')); newUnsavedValue = value.trim() || (isJsonArray ? '[]' : '{}'); try { JSON.parse(newUnsavedValue); } catch (e) { - isInvalid = true; - error = i18n.translate('advancedSettings.field.codeEditorSyntaxErrorMessage', { - defaultMessage: 'Invalid JSON syntax', - }); + errorParams = { + error: i18n.translate('advancedSettings.field.codeEditorSyntaxErrorMessage', { + defaultMessage: 'Invalid JSON syntax', + }), + isInvalid: true, + }; } break; default: newUnsavedValue = value; } - this.setState({ - error, - isInvalid, - unsavedValue: newUnsavedValue, + this.handleChange({ + value: newUnsavedValue, + ...errorParams, }); }; @@ -201,58 +176,44 @@ export class Field extends PureComponent { onFieldChangeEvent = (e: React.ChangeEvent) => this.onFieldChange(e.target.value); - onFieldChange = (value: any) => { - const { type, validation } = this.props.setting; - const { unsavedValue } = this.state; - + onFieldChange = (targetValue: any) => { + const { type, validation, value, defVal } = this.props.setting; let newUnsavedValue; switch (type) { case 'boolean': - newUnsavedValue = !unsavedValue; + const { unsavedChanges } = this.props; + const currentValue = unsavedChanges + ? unsavedChanges.value + : getEditableValue(type, value, defVal); + newUnsavedValue = !currentValue; break; case 'number': - newUnsavedValue = Number(value); + newUnsavedValue = Number(targetValue); break; default: - newUnsavedValue = value; + newUnsavedValue = targetValue; } - let isInvalid = false; - let error = null; + let errorParams = {}; - if (validation && (validation as StringValidationRegex).regex) { + if ((validation as StringValidationRegex)?.regex) { if (!(validation as StringValidationRegex).regex!.test(newUnsavedValue.toString())) { - error = (validation as StringValidationRegex).message; - isInvalid = true; + errorParams = { + error: (validation as StringValidationRegex).message, + isInvalid: true, + }; } } - this.setState({ - unsavedValue: newUnsavedValue, - isInvalid, - error, + this.handleChange({ + value: newUnsavedValue, + ...errorParams, }); }; - onFieldKeyDown = ({ keyCode }: { keyCode: number }) => { - if (keyCode === keyCodes.ENTER) { - this.saveEdit(); - } - if (keyCode === keyCodes.ESCAPE) { - this.cancelEdit(); - } - }; - - onFieldEscape = ({ keyCode }: { keyCode: number }) => { - if (keyCode === keyCodes.ESCAPE) { - this.cancelEdit(); - } - }; - onImageChange = async (files: any[]) => { if (!files.length) { - this.clearError(); this.setState({ unsavedValue: null, }); @@ -266,19 +227,24 @@ export class Field extends PureComponent { if (file instanceof File) { base64Image = (await this.getImageAsBase64(file)) as string; } - const isInvalid = !!(maxSize && maxSize.length && base64Image.length > maxSize.length); - this.setState({ - isInvalid, - error: isInvalid - ? i18n.translate('advancedSettings.field.imageTooLargeErrorMessage', { - defaultMessage: 'Image is too large, maximum size is {maxSizeDescription}', - values: { - maxSizeDescription: maxSize.description, - }, - }) - : null, + + let errorParams = {}; + const isInvalid = !!(maxSize?.length && base64Image.length > maxSize.length); + if (isInvalid) { + errorParams = { + isInvalid, + error: i18n.translate('advancedSettings.field.imageTooLargeErrorMessage', { + defaultMessage: 'Image is too large, maximum size is {maxSizeDescription}', + values: { + maxSizeDescription: maxSize.description, + }, + }), + }; + } + this.handleChange({ changeImage: true, - unsavedValue: base64Image, + value: base64Image, + ...errorParams, }); } catch (err) { this.props.toasts.addDanger( @@ -305,152 +271,62 @@ export class Field extends PureComponent { } changeImage = () => { - this.setState({ + this.handleChange({ + value: null, changeImage: true, }); }; cancelChangeImage = () => { - const { savedValue } = this.state; - - if (this.changeImageForm) { - this.changeImageForm.fileInput.value = null; - this.changeImageForm.handleChange(); - } - - this.setState({ - changeImage: false, - unsavedValue: savedValue, - }); - }; - - cancelEdit = () => { - const { savedValue } = this.state; - this.clearError(); - this.setState({ - unsavedValue: savedValue, - }); - }; - - showPageReloadToast = () => { - if (this.props.setting.requiresPageReload) { - this.props.toasts.add({ - title: i18n.translate('advancedSettings.field.requiresPageReloadToastDescription', { - defaultMessage: 'Please reload the page for the "{settingName}" setting to take effect.', - values: { - settingName: this.props.setting.displayName || this.props.setting.name, - }, - }), - text: element => { - const content = ( - <> - - - window.location.reload()}> - {i18n.translate('advancedSettings.field.requiresPageReloadToastButtonLabel', { - defaultMessage: 'Reload page', - })} - - - - - ); - ReactDOM.render(content, element); - return () => ReactDOM.unmountComponentAtNode(element); - }, - color: 'success', - }); - } - }; - - saveEdit = async () => { - const { name, defVal, type } = this.props.setting; - const { changeImage, savedValue, unsavedValue, isJsonArray } = this.state; - - if (savedValue === unsavedValue) { - return; - } - - let valueToSave = unsavedValue; - let isSameValue = false; - - switch (type) { - case 'array': - valueToSave = valueToSave.split(',').map((val: string) => val.trim()); - isSameValue = valueToSave.join(',') === (defVal as string[]).join(','); - break; - case 'json': - valueToSave = valueToSave.trim(); - valueToSave = valueToSave || (isJsonArray ? '[]' : '{}'); - default: - isSameValue = valueToSave === defVal; - } - - this.setLoading(true); - try { - if (isSameValue) { - await this.props.clear(name); - } else { - await this.props.save(name, valueToSave); - } - - this.showPageReloadToast(); - - if (changeImage) { - this.cancelChangeImage(); - } - } catch (e) { - this.props.toasts.addDanger( - i18n.translate('advancedSettings.field.saveFieldErrorMessage', { - defaultMessage: 'Unable to save {name}', - values: { name }, - }) - ); + if (this.changeImageForm.current) { + this.changeImageForm.current.fileInput.value = null; + this.changeImageForm.current.handleChange({}); } - this.setLoading(false); - }; - - resetField = async () => { - const { name } = this.props.setting; - this.setLoading(true); - try { - await this.props.clear(name); - this.showPageReloadToast(); - this.cancelChangeImage(); - this.clearError(); - } catch (e) { - this.props.toasts.addDanger( - i18n.translate('advancedSettings.field.resetFieldErrorMessage', { - defaultMessage: 'Unable to reset {name}', - values: { name }, - }) - ); + if (this.props.clearChange) { + this.props.clearChange(this.props.setting.name); } - this.setLoading(false); }; - renderField(setting: FieldSetting) { - const { enableSaving } = this.props; - const { loading, changeImage, unsavedValue } = this.state; - const { name, value, type, options, optionLabels = {}, isOverridden, ariaName } = setting; + renderField(id: string, setting: FieldSetting) { + const { enableSaving, unsavedChanges, loading } = this.props; + const { + name, + value, + type, + options, + optionLabels = {}, + isOverridden, + defVal, + ariaName, + } = setting; + const a11yProps: { [key: string]: string } = unsavedChanges + ? { + 'aria-label': ariaName, + 'aria-describedby': id, + } + : { + 'aria-label': ariaName, + }; + const currentValue = unsavedChanges + ? unsavedChanges.value + : getEditableValue(type, value, defVal); switch (type) { case 'boolean': return ( ) : ( ) } - checked={!!unsavedValue} + checked={!!currentValue} onChange={this.onFieldChangeSwitch} disabled={loading || isOverridden || !enableSaving} - onKeyDown={this.onFieldKeyDown} data-test-subj={`advancedSetting-editField-${name}`} - aria-label={ariaName} + {...a11yProps} /> ); case 'markdown': @@ -458,10 +334,10 @@ export class Field extends PureComponent { return (
{ $blockScrolling: Infinity, }} showGutter={false} + fullWidth />
); case 'image': + const changeImage = unsavedChanges?.changeImage; if (!isDefaultValue(setting) && !changeImage) { - return ( - - ); + return ; } else { return ( { - this.changeImageForm = input; - }} - onKeyDown={this.onFieldEscape} + ref={this.changeImageForm} + fullWidth data-test-subj={`advancedSetting-editField-${name}`} /> ); @@ -501,8 +375,8 @@ export class Field extends PureComponent { case 'select': return ( { return { text: optionLabels.hasOwnProperty(option) ? optionLabels[option] : option, @@ -512,31 +386,31 @@ export class Field extends PureComponent { onChange={this.onFieldChangeEvent} isLoading={loading} disabled={loading || isOverridden || !enableSaving} - onKeyDown={this.onFieldKeyDown} + fullWidth data-test-subj={`advancedSetting-editField-${name}`} /> ); case 'number': return ( ); default: return ( ); @@ -699,8 +573,12 @@ export class Field extends PureComponent { } renderResetToDefaultLink(setting: FieldSetting) { - const { ariaName, name } = setting; - if (isDefaultValue(setting)) { + const { defVal, ariaName, name } = setting; + if ( + defVal === this.props.unsavedChanges?.value || + isDefaultValue(setting) || + this.props.loading + ) { return; } return ( @@ -726,7 +604,7 @@ export class Field extends PureComponent { } renderChangeImageLink(setting: FieldSetting) { - const { changeImage } = this.state; + const changeImage = this.props.unsavedChanges?.changeImage; const { type, value, ariaName, name } = setting; if (type !== 'image' || !value || changeImage) { return; @@ -752,84 +630,49 @@ export class Field extends PureComponent { ); } - renderActions(setting: FieldSetting) { - const { ariaName, name } = setting; - const { loading, isInvalid, changeImage, savedValue, unsavedValue } = this.state; - const isDisabled = loading || setting.isOverridden; - - if (savedValue === unsavedValue && !changeImage) { - return; - } - - return ( - - - - - - - - - (changeImage ? this.cancelChangeImage() : this.cancelEdit())} - disabled={isDisabled} - data-test-subj={`advancedSetting-cancelEditField-${name}`} - > - - - - - - ); - } - render() { - const { setting } = this.props; - const { error, isInvalid } = this.state; + const { setting, unsavedChanges } = this.props; + const error = unsavedChanges?.error; + const isInvalid = unsavedChanges?.isInvalid; + + const className = classNames('mgtAdvancedSettings__field', { + 'mgtAdvancedSettings__field--unsaved': unsavedChanges, + 'mgtAdvancedSettings__field--invalid': isInvalid, + }); + const id = setting.name; return ( - - - - - {this.renderField(setting)} - - - - {this.renderActions(setting)} - + + + <> + {this.renderField(id, setting)} + {unsavedChanges && ( + +

+ {unsavedChanges.error + ? unsavedChanges.error + : i18n.translate('advancedSettings.field.settingIsUnsaved', { + defaultMessage: 'Setting is currently not saved.', + })} +

+
+ )} + +
+
); } } diff --git a/src/plugins/advanced_settings/public/management_app/components/field/index.ts b/src/plugins/advanced_settings/public/management_app/components/field/index.ts index 5c86519116fe9..d1b9b34515532 100644 --- a/src/plugins/advanced_settings/public/management_app/components/field/index.ts +++ b/src/plugins/advanced_settings/public/management_app/components/field/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export { Field } from './field'; +export { Field, getEditableValue } from './field'; diff --git a/src/plugins/advanced_settings/public/management_app/components/form/__snapshots__/form.test.tsx.snap b/src/plugins/advanced_settings/public/management_app/components/form/__snapshots__/form.test.tsx.snap index 8c471f5f5be9c..bce9cb67537db 100644 --- a/src/plugins/advanced_settings/public/management_app/components/form/__snapshots__/form.test.tsx.snap +++ b/src/plugins/advanced_settings/public/management_app/components/form/__snapshots__/form.test.tsx.snap @@ -1,449 +1,849 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Form should not render no settings message when instructed not to 1`] = ``; +exports[`Form should not render no settings message when instructed not to 1`] = ` + +
+ + + + + +

+ General +

+
+
+
+ + + +
+
+ + + + + + +

+ Dashboard +

+
+
+
+ + +
+
+ + + + + + +

+ X-pack +

+
+ + + + + + + , + "settingsCount": 9, + } + } + /> + + +
+
+ + +
+
+ +
+
+`; exports[`Form should render no settings message when there are no settings 1`] = ` - - + + + + - - , - } - } + +

+ General +

+
+
+
+ + + +
+
+ -
+ + + + + +

+ Dashboard +

+
+
+
+ + +
+
+ + + + + + +

+ X-pack +

+
+ + + + + + + , + "settingsCount": 9, + } + } + /> + + +
+
+ + +
+
+ +
`; exports[`Form should render normally 1`] = ` - - - - - + + + + -

- General -

-
-
-
- - +

+ General +

+ + + + + - + -
-
- - - - - - + + + + + + + -

- Dashboard -

- -
-
- - +

+ Dashboard +

+ + + + + -
-
- - - - - - -

- X-pack -

-
- +
+
+ + + + + - - - - - - , - "settingsCount": 9, + +

+ X-pack +

+
+ + + + + + + , + "settingsCount": 9, + } } - } - /> - - -
-
- - + + + + + + -
-
- + toasts={Object {}} + /> + + + +
`; exports[`Form should render read-only when saving is disabled 1`] = ` - - - - - + + + + -

- General -

-
-
-
- - +

+ General +

+
+
+ + + - + - - - - - - - - + + + + + + + -

- Dashboard -

- -
-
- - +

+ Dashboard +

+ + + + + -
-
- - - - - - -

- X-pack -

-
- +
+
+ + + + + - - - - - - , - "settingsCount": 9, + +

+ X-pack +

+
+ + + + + + + , + "settingsCount": 9, + } } - } - /> - - -
-
- - + + + + + + -
-
- + toasts={Object {}} + /> + + + +
`; diff --git a/src/plugins/advanced_settings/public/management_app/components/form/_form.scss b/src/plugins/advanced_settings/public/management_app/components/form/_form.scss new file mode 100644 index 0000000000000..02ebb90221d90 --- /dev/null +++ b/src/plugins/advanced_settings/public/management_app/components/form/_form.scss @@ -0,0 +1,13 @@ +@import '@elastic/eui/src/components/header/variables'; +@import '@elastic/eui/src/components/nav_drawer/variables'; + +.mgtAdvancedSettingsForm__bottomBar { + margin-left: $euiNavDrawerWidthCollapsed; + z-index: 9; // Puts it inuder the nav drawer when expanded + &--pushForNav { + margin-left: $euiNavDrawerWidthExpanded; + } + @include euiBreakpoint('xs', 's') { + margin-left: 0; + } +} diff --git a/src/plugins/advanced_settings/public/management_app/components/form/_index.scss b/src/plugins/advanced_settings/public/management_app/components/form/_index.scss new file mode 100644 index 0000000000000..2ef4ef1d20ce9 --- /dev/null +++ b/src/plugins/advanced_settings/public/management_app/components/form/_index.scss @@ -0,0 +1 @@ +@import './form'; diff --git a/src/plugins/advanced_settings/public/management_app/components/form/form.test.tsx b/src/plugins/advanced_settings/public/management_app/components/form/form.test.tsx index 468cfbfc70820..0e942665b23a9 100644 --- a/src/plugins/advanced_settings/public/management_app/components/form/form.test.tsx +++ b/src/plugins/advanced_settings/public/management_app/components/form/form.test.tsx @@ -18,9 +18,14 @@ */ import React from 'react'; -import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers'; +import { shallowWithI18nProvider, mountWithI18nProvider } from 'test_utils/enzyme_helpers'; import { UiSettingsType } from '../../../../../../core/public'; +// @ts-ignore +import { findTestSubject } from '@elastic/eui/lib/test'; + +import { notificationServiceMock } from '../../../../../../core/public/mocks'; +import { SettingsChanges } from '../../types'; import { Form } from './form'; jest.mock('../field', () => ({ @@ -29,6 +34,25 @@ jest.mock('../field', () => ({ }, })); +beforeAll(() => { + const localStorage: Record = { + 'core.chrome.isLocked': true, + }; + + Object.defineProperty(window, 'localStorage', { + value: { + getItem: (key: string) => { + return localStorage[key] || null; + }, + }, + writable: true, + }); +}); + +afterAll(() => { + delete (window as any).localStorage; +}); + const defaults = { requiresPageReload: false, readOnly: false, @@ -43,50 +67,52 @@ const defaults = { const settings = { dashboard: [ { + ...defaults, name: 'dashboard:test:setting', ariaName: 'dashboard test setting', displayName: 'Dashboard test setting', category: ['dashboard'], - ...defaults, + requiresPageReload: true, }, ], general: [ { + ...defaults, name: 'general:test:date', ariaName: 'general test date', displayName: 'Test date', description: 'bar', category: ['general'], - ...defaults, }, { + ...defaults, name: 'setting:test', ariaName: 'setting test', displayName: 'Test setting', description: 'foo', category: ['general'], - ...defaults, }, ], 'x-pack': [ { + ...defaults, name: 'xpack:test:setting', ariaName: 'xpack test setting', displayName: 'X-Pack test setting', category: ['x-pack'], description: 'bar', - ...defaults, }, ], }; + const categories = ['general', 'dashboard', 'hiddenCategory', 'x-pack']; const categoryCounts = { general: 2, dashboard: 1, 'x-pack': 10, }; -const save = (key: string, value: any) => Promise.resolve(true); -const clear = (key: string) => Promise.resolve(true); +const save = jest.fn((changes: SettingsChanges) => Promise.resolve([true])); + const clearQuery = () => {}; describe('Form', () => { @@ -94,10 +120,10 @@ describe('Form', () => { const component = shallowWithI18nProvider( { const component = shallowWithI18nProvider( { const component = shallowWithI18nProvider( { const component = shallowWithI18nProvider( { expect(component).toMatchSnapshot(); }); + + it('should hide bottom bar when clicking on the cancel changes button', async () => { + const wrapper = mountWithI18nProvider( + + ); + (wrapper.instance() as Form).setState({ + unsavedChanges: { + 'dashboard:test:setting': { + value: 'changedValue', + }, + }, + }); + const updated = wrapper.update(); + expect(updated.exists('[data-test-subj="advancedSetting-bottomBar"]')).toEqual(true); + await findTestSubject(updated, `advancedSetting-cancelButton`).simulate('click'); + updated.update(); + expect(updated.exists('[data-test-subj="advancedSetting-bottomBar"]')).toEqual(false); + }); + + it('should show a reload toast when saving setting requiring a page reload', async () => { + const toasts = notificationServiceMock.createStartContract().toasts; + const wrapper = mountWithI18nProvider( + + ); + (wrapper.instance() as Form).setState({ + unsavedChanges: { + 'dashboard:test:setting': { + value: 'changedValue', + }, + }, + }); + const updated = wrapper.update(); + + findTestSubject(updated, `advancedSetting-saveButton`).simulate('click'); + expect(save).toHaveBeenCalled(); + await save({ 'dashboard:test:setting': 'changedValue' }); + expect(toasts.add).toHaveBeenCalledWith( + expect.objectContaining({ + title: expect.stringContaining( + 'One or more settings require you to reload the page to take effect.' + ), + }) + ); + }); }); diff --git a/src/plugins/advanced_settings/public/management_app/components/form/form.tsx b/src/plugins/advanced_settings/public/management_app/components/form/form.tsx index 91d587866836e..ef433dd990d33 100644 --- a/src/plugins/advanced_settings/public/management_app/components/form/form.tsx +++ b/src/plugins/advanced_settings/public/management_app/components/form/form.tsx @@ -18,7 +18,7 @@ */ import React, { PureComponent, Fragment } from 'react'; - +import classNames from 'classnames'; import { EuiFlexGroup, EuiFlexItem, @@ -27,30 +27,188 @@ import { EuiPanel, EuiSpacer, EuiText, + EuiTextColor, + EuiBottomBar, + EuiButton, + EuiToolTip, + EuiButtonEmpty, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { isEmpty } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { toMountPoint } from '../../../../../kibana_react/public'; import { DocLinksStart, ToastsStart } from '../../../../../../core/public'; import { getCategoryName } from '../../lib'; -import { Field } from '../field'; -import { FieldSetting } from '../../types'; +import { Field, getEditableValue } from '../field'; +import { FieldSetting, SettingsChanges, FieldState } from '../../types'; type Category = string; +const NAV_IS_LOCKED_KEY = 'core.chrome.isLocked'; interface FormProps { settings: Record; + visibleSettings: Record; categories: Category[]; categoryCounts: Record; clearQuery: () => void; - save: (key: string, value: any) => Promise; - clear: (key: string) => Promise; + save: (changes: SettingsChanges) => Promise; showNoResultsMessage: boolean; enableSaving: boolean; dockLinks: DocLinksStart['links']; toasts: ToastsStart; } +interface FormState { + unsavedChanges: { + [key: string]: FieldState; + }; + loading: boolean; +} + export class Form extends PureComponent { + state: FormState = { + unsavedChanges: {}, + loading: false, + }; + + setLoading(loading: boolean) { + this.setState({ + loading, + }); + } + + getSettingByKey = (key: string): FieldSetting | undefined => { + return Object.values(this.props.settings) + .flat() + .find(el => el.name === key); + }; + + getCountOfUnsavedChanges = (): number => { + return Object.keys(this.state.unsavedChanges).length; + }; + + getCountOfHiddenUnsavedChanges = (): number => { + const shownSettings = Object.values(this.props.visibleSettings) + .flat() + .map(setting => setting.name); + return Object.keys(this.state.unsavedChanges).filter(key => !shownSettings.includes(key)) + .length; + }; + + areChangesInvalid = (): boolean => { + const { unsavedChanges } = this.state; + return Object.values(unsavedChanges).some(({ isInvalid }) => isInvalid); + }; + + handleChange = (key: string, change: FieldState) => { + const setting = this.getSettingByKey(key); + if (!setting) { + return; + } + const { type, defVal, value } = setting; + const savedValue = getEditableValue(type, value, defVal); + if (change.value === savedValue) { + return this.clearChange(key); + } + this.setState({ + unsavedChanges: { + ...this.state.unsavedChanges, + [key]: change, + }, + }); + }; + + clearChange = (key: string) => { + if (!this.state.unsavedChanges[key]) { + return; + } + const unsavedChanges = { ...this.state.unsavedChanges }; + delete unsavedChanges[key]; + + this.setState({ + unsavedChanges, + }); + }; + + clearAllUnsaved = () => { + this.setState({ unsavedChanges: {} }); + }; + + saveAll = async () => { + this.setLoading(true); + const { unsavedChanges } = this.state; + + if (isEmpty(unsavedChanges)) { + return; + } + const configToSave: SettingsChanges = {}; + let requiresReload = false; + + Object.entries(unsavedChanges).forEach(([name, { value }]) => { + const setting = this.getSettingByKey(name); + if (!setting) { + return; + } + const { defVal, type, requiresPageReload } = setting; + let valueToSave = value; + let equalsToDefault = false; + switch (type) { + case 'array': + valueToSave = valueToSave.split(',').map((val: string) => val.trim()); + equalsToDefault = valueToSave.join(',') === (defVal as string[]).join(','); + break; + case 'json': + const isArray = Array.isArray(JSON.parse((defVal as string) || '{}')); + valueToSave = valueToSave.trim(); + valueToSave = valueToSave || (isArray ? '[]' : '{}'); + default: + equalsToDefault = valueToSave === defVal; + } + if (requiresPageReload) { + requiresReload = true; + } + configToSave[name] = equalsToDefault ? null : valueToSave; + }); + + try { + await this.props.save(configToSave); + this.clearAllUnsaved(); + if (requiresReload) { + this.renderPageReloadToast(); + } + } catch (e) { + this.props.toasts.addDanger( + i18n.translate('advancedSettings.form.saveErrorMessage', { + defaultMessage: 'Unable to save', + }) + ); + } + this.setLoading(false); + }; + + renderPageReloadToast = () => { + this.props.toasts.add({ + title: i18n.translate('advancedSettings.form.requiresPageReloadToastDescription', { + defaultMessage: 'One or more settings require you to reload the page to take effect.', + }), + text: toMountPoint( + <> + + + window.location.reload()}> + {i18n.translate('advancedSettings.form.requiresPageReloadToastButtonLabel', { + defaultMessage: 'Reload page', + })} + + + + + ), + color: 'success', + }); + }; + renderClearQueryLink(totalSettings: number, currentSettings: number) { const { clearQuery } = this.props; @@ -102,8 +260,9 @@ export class Form extends PureComponent { { return null; } + renderCountOfUnsaved = () => { + const unsavedCount = this.getCountOfUnsavedChanges(); + const hiddenUnsavedCount = this.getCountOfHiddenUnsavedChanges(); + return ( + + + + ); + }; + + renderBottomBar = () => { + const areChangesInvalid = this.areChangesInvalid(); + const bottomBarClasses = classNames('mgtAdvancedSettingsForm__bottomBar', { + 'mgtAdvancedSettingsForm__bottomBar--pushForNav': + localStorage.getItem(NAV_IS_LOCKED_KEY) === 'true', + }); + return ( + + + +

{this.renderCountOfUnsaved()}

+
+ + + + + {i18n.translate('advancedSettings.form.cancelButtonLabel', { + defaultMessage: 'Cancel changes', + })} + + + + + + {i18n.translate('advancedSettings.form.saveButtonLabel', { + defaultMessage: 'Save changes', + })} + + + + + +
+
+ ); + }; + render() { - const { settings, categories, categoryCounts, clearQuery } = this.props; + const { unsavedChanges } = this.state; + const { visibleSettings, categories, categoryCounts, clearQuery } = this.props; const currentCategories: Category[] = []; categories.forEach(category => { - if (settings[category] && settings[category].length) { + if (visibleSettings[category] && visibleSettings[category].length) { currentCategories.push(category); } }); return ( - {currentCategories.length - ? currentCategories.map(category => { - return this.renderCategory(category, settings[category], categoryCounts[category]); - }) - : this.maybeRenderNoSettings(clearQuery)} +
+ {currentCategories.length + ? currentCategories.map(category => { + return this.renderCategory( + category, + visibleSettings[category], + categoryCounts[category] + ); + }) + : this.maybeRenderNoSettings(clearQuery)} +
+ {!isEmpty(unsavedChanges) && this.renderBottomBar()}
); } diff --git a/src/plugins/advanced_settings/public/management_app/types.ts b/src/plugins/advanced_settings/public/management_app/types.ts index 05bb5e754563d..d44a05ce36f5d 100644 --- a/src/plugins/advanced_settings/public/management_app/types.ts +++ b/src/plugins/advanced_settings/public/management_app/types.ts @@ -47,6 +47,19 @@ export interface FieldSetting { } // until eui searchbar and query are typed + +export interface SettingsChanges { + [key: string]: any; +} + +export interface FieldState { + value?: any; + changeImage?: boolean; + loading?: boolean; + isInvalid?: boolean; + error?: string | null; +} + export interface IQuery { ast: any; // incomplete text: string; diff --git a/src/plugins/telemetry/public/components/telemetry_management_section.tsx b/src/plugins/telemetry/public/components/telemetry_management_section.tsx index 20c8873b13272..bf14c33a48048 100644 --- a/src/plugins/telemetry/public/components/telemetry_management_section.tsx +++ b/src/plugins/telemetry/public/components/telemetry_management_section.tsx @@ -33,8 +33,8 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { PRIVACY_STATEMENT_URL } from '../../common/constants'; import { OptInExampleFlyout } from './opt_in_example_flyout'; -// @ts-ignore import { Field } from '../../../advanced_settings/public'; +import { ToastsStart } from '../../../../core/public/'; import { TelemetryService } from '../services/telemetry_service'; const SEARCH_TERMS = ['telemetry', 'usage', 'data', 'usage data']; @@ -44,12 +44,14 @@ interface Props { showAppliesSettingMessage: boolean; enableSaving: boolean; query?: any; + toasts: ToastsStart; } interface State { processing: boolean; showExample: boolean; queryMatches: boolean | null; + enabled: boolean; } export class TelemetryManagementSection extends Component { @@ -57,6 +59,7 @@ export class TelemetryManagementSection extends Component { processing: false, showExample: false, queryMatches: null, + enabled: this.props.telemetryService.getIsOptedIn() || false, }; UNSAFE_componentWillReceiveProps(nextProps: Props) { @@ -79,7 +82,7 @@ export class TelemetryManagementSection extends Component { render() { const { telemetryService } = this.props; - const { showExample, queryMatches } = this.state; + const { showExample, queryMatches, enabled, processing } = this.state; if (!telemetryService.getCanChangeOptInStatus()) { return null; @@ -119,7 +122,7 @@ export class TelemetryManagementSection extends Component { displayName: i18n.translate('telemetry.provideUsageStatisticsTitle', { defaultMessage: 'Provide usage statistics', }), - value: telemetryService.getIsOptedIn(), + value: enabled, description: this.renderDescription(), defVal: true, ariaName: i18n.translate('telemetry.provideUsageStatisticsAriaName', { @@ -127,10 +130,10 @@ export class TelemetryManagementSection extends Component { }), } as any } + loading={processing} dockLinks={null as any} toasts={null as any} - save={this.toggleOptIn} - clear={this.toggleOptIn} + handleChange={this.toggleOptIn} enableSaving={this.props.enableSaving} /> @@ -151,13 +154,13 @@ export class TelemetryManagementSection extends Component {

), @@ -200,20 +203,35 @@ export class TelemetryManagementSection extends Component { ); toggleOptIn = async (): Promise => { - const { telemetryService } = this.props; - const newOptInValue = !telemetryService.getIsOptedIn(); + const { telemetryService, toasts } = this.props; + const newOptInValue = !this.state.enabled; return new Promise((resolve, reject) => { - this.setState({ processing: true }, async () => { - try { - await telemetryService.setOptIn(newOptInValue); - this.setState({ processing: false }); - resolve(true); - } catch (err) { - this.setState({ processing: false }); - reject(err); + this.setState( + { + processing: true, + enabled: newOptInValue, + }, + async () => { + try { + await telemetryService.setOptIn(newOptInValue); + this.setState({ processing: false }); + toasts.addSuccess( + newOptInValue + ? i18n.translate('telemetry.optInSuccessOn', { + defaultMessage: 'Usage data collection turned on.', + }) + : i18n.translate('telemetry.optInSuccessOff', { + defaultMessage: 'Usage data collection turned off.', + }) + ); + resolve(true); + } catch (err) { + this.setState({ processing: false }); + reject(err); + } } - }); + ); }); }; diff --git a/test/functional/page_objects/settings_page.ts b/test/functional/page_objects/settings_page.ts index d7e5064cf7280..ff340c6b0abcd 100644 --- a/test/functional/page_objects/settings_page.ts +++ b/test/functional/page_objects/settings_page.ts @@ -94,7 +94,7 @@ export function SettingsPageProvider({ getService, getPageObjects }: FtrProvider `[data-test-subj="advancedSetting-editField-${propertyName}"] option[value="${propertyValue}"]` ); await PageObjects.header.waitUntilLoadingHasFinished(); - await testSubjects.click(`advancedSetting-saveEditField-${propertyName}`); + await testSubjects.click(`advancedSetting-saveButton`); await PageObjects.header.waitUntilLoadingHasFinished(); } @@ -102,14 +102,14 @@ export function SettingsPageProvider({ getService, getPageObjects }: FtrProvider const input = await testSubjects.find(`advancedSetting-editField-${propertyName}`); await input.clearValue(); await input.type(propertyValue); - await testSubjects.click(`advancedSetting-saveEditField-${propertyName}`); + await testSubjects.click(`advancedSetting-saveButton`); await PageObjects.header.waitUntilLoadingHasFinished(); } async toggleAdvancedSettingCheckbox(propertyName: string) { testSubjects.click(`advancedSetting-editField-${propertyName}`); await PageObjects.header.waitUntilLoadingHasFinished(); - await testSubjects.click(`advancedSetting-saveEditField-${propertyName}`); + await testSubjects.click(`advancedSetting-saveButton`); await PageObjects.header.waitUntilLoadingHasFinished(); } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 4b06645cdfe04..78bb39dd22dea 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1618,8 +1618,6 @@ "advancedSettings.categoryNames.timelionLabel": "Timelion", "advancedSettings.categoryNames.visualizationsLabel": "ビジュアライゼーション", "advancedSettings.categorySearchLabel": "カテゴリー", - "advancedSettings.field.cancelEditingButtonAriaLabel": "{ariaName} の編集をキャンセル", - "advancedSettings.field.cancelEditingButtonLabel": "キャンセル", "advancedSettings.field.changeImageLinkAriaLabel": "{ariaName} を変更", "advancedSettings.field.changeImageLinkText": "画像を変更", "advancedSettings.field.codeEditorSyntaxErrorMessage": "無効な JSON 構文", @@ -1632,17 +1630,10 @@ "advancedSettings.field.imageTooLargeErrorMessage": "画像が大きすぎます。最大サイズは {maxSizeDescription} です", "advancedSettings.field.offLabel": "オフ", "advancedSettings.field.onLabel": "オン", - "advancedSettings.field.requiresPageReloadToastButtonLabel": "ページを再読み込み", - "advancedSettings.field.requiresPageReloadToastDescription": "「{settingName}」設定を有効にするには、ページを再読み込みしてください。", - "advancedSettings.field.resetFieldErrorMessage": "{name} をリセットできませんでした", "advancedSettings.field.resetToDefaultLinkAriaLabel": "{ariaName} をデフォルトにリセット", "advancedSettings.field.resetToDefaultLinkText": "デフォルトにリセット", - "advancedSettings.field.saveButtonAriaLabel": "{ariaName} を保存", - "advancedSettings.field.saveButtonLabel": "保存", - "advancedSettings.field.saveFieldErrorMessage": "{name} を保存できませんでした", "advancedSettings.form.clearNoSearchResultText": "(検索結果を消去)", "advancedSettings.form.clearSearchResultText": "(検索結果を消去)", - "advancedSettings.form.noSearchResultText": "設定が見つかりませんでした {clearSearch}", "advancedSettings.form.searchResultText": "検索用語により {settingsCount} 件の設定が非表示になっています {clearSearch}", "advancedSettings.pageTitle": "設定", "advancedSettings.searchBar.unableToParseQueryErrorMessage": "クエリをパースできません", @@ -2474,8 +2465,6 @@ "statusPage.statusApp.statusTitle": "プラグインステータス", "statusPage.statusTable.columns.idHeader": "ID", "statusPage.statusTable.columns.statusHeader": "ステータス", - "telemetry.callout.appliesSettingTitle": "この設定は {allOfKibanaText} に適用されます", - "telemetry.callout.appliesSettingTitle.allOfKibanaText": "Kibana のすべて", "telemetry.callout.clusterStatisticsDescription": "これは収集される基本的なクラスター統計の例です。インデックス、シャード、ノードの数が含まれます。監視がオンになっているかどうかなどのハイレベルの使用統計も含まれます。", "telemetry.callout.clusterStatisticsTitle": "クラスター統計", "telemetry.callout.errorLoadingClusterStatisticsDescription": "クラスター統計の取得中に予期せぬエラーが発生しました。Elasticsearch、Kibana、またはネットワークのエラーが原因の可能性があります。Kibana を確認し、ページを再読み込みして再試行してください。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index ecf4dfbb33be6..fc9dacf0e50f7 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1618,8 +1618,6 @@ "advancedSettings.categoryNames.timelionLabel": "Timelion", "advancedSettings.categoryNames.visualizationsLabel": "可视化", "advancedSettings.categorySearchLabel": "类别", - "advancedSettings.field.cancelEditingButtonAriaLabel": "取消编辑 {ariaName}", - "advancedSettings.field.cancelEditingButtonLabel": "取消", "advancedSettings.field.changeImageLinkAriaLabel": "更改 {ariaName}", "advancedSettings.field.changeImageLinkText": "更改图片", "advancedSettings.field.codeEditorSyntaxErrorMessage": "JSON 语法无效", @@ -1632,14 +1630,8 @@ "advancedSettings.field.imageTooLargeErrorMessage": "图像过大,最大大小为 {maxSizeDescription}", "advancedSettings.field.offLabel": "关闭", "advancedSettings.field.onLabel": "开启", - "advancedSettings.field.requiresPageReloadToastButtonLabel": "重新加载页面", - "advancedSettings.field.requiresPageReloadToastDescription": "请重新加载页面,以使“{settingName}”设置生效。", - "advancedSettings.field.resetFieldErrorMessage": "无法重置 {name}", "advancedSettings.field.resetToDefaultLinkAriaLabel": "将 {ariaName} 重置为默认值", "advancedSettings.field.resetToDefaultLinkText": "重置为默认值", - "advancedSettings.field.saveButtonAriaLabel": "保存 {ariaName}", - "advancedSettings.field.saveButtonLabel": "保存", - "advancedSettings.field.saveFieldErrorMessage": "无法保存 {name}", "advancedSettings.form.clearNoSearchResultText": "(清除搜索)", "advancedSettings.form.clearSearchResultText": "(清除搜索)", "advancedSettings.form.noSearchResultText": "未找到设置{clearSearch}", @@ -2474,8 +2466,6 @@ "statusPage.statusApp.statusTitle": "插件状态", "statusPage.statusTable.columns.idHeader": "ID", "statusPage.statusTable.columns.statusHeader": "状态", - "telemetry.callout.appliesSettingTitle": "此设置适用于{allOfKibanaText}", - "telemetry.callout.appliesSettingTitle.allOfKibanaText": "所有 Kibana。", "telemetry.callout.clusterStatisticsDescription": "这是我们将收集的基本集群统计信息的示例。其包括索引、分片和节点的数目。还包括概括性的使用情况统计信息,例如监测是否打开。", "telemetry.callout.clusterStatisticsTitle": "集群统计信息", "telemetry.callout.errorLoadingClusterStatisticsDescription": "尝试提取集群统计信息时发生意外错误。发生此问题的原因可能是 Elasticsearch 出故障、Kibana 出故障或者有网络错误。检查 Kibana,然后重新加载页面并重试。", From 256e4ab67c7fccae9aae38aac22f3788466f8b2f Mon Sep 17 00:00:00 2001 From: Brandon Kobel Date: Mon, 24 Feb 2020 09:40:37 -0800 Subject: [PATCH 024/123] Adding xpack.encryptedSavedObjects.encryptionKey to docker allow-list (#58291) Co-authored-by: Elastic Machine --- .../os_packages/docker_generator/resources/bin/kibana-docker | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker index 34ba25f92beb6..d4d2e86e1e96b 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker @@ -142,6 +142,7 @@ kibana_vars=( xpack.code.security.enableGitCertCheck xpack.code.security.gitHostWhitelist xpack.code.security.gitProtocolWhitelist + xpack.encryptedSavedObjects.encryptionKey xpack.graph.enabled xpack.graph.canEditDrillDownUrls xpack.graph.savePolicy From b88b99140bc0d63036c0789d1ddc8dc9597e2b5e Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Mon, 24 Feb 2020 18:44:24 +0100 Subject: [PATCH 025/123] [ML] Fix transforms license check. (#58343) Fixes an error where the transforms page would load blank with an expired license. Fixes the issue by adding a type guard. With an expired license, the page now renders again correctly the error message. --- .../lib/authorization/components/common.ts | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/common.ts b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/common.ts index 5aec2ac041db3..27556e0d673a8 100644 --- a/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/common.ts +++ b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/common.ts @@ -21,19 +21,33 @@ export interface Privileges { missingPrivileges: MissingPrivileges; } +function isPrivileges(arg: any): arg is Privileges { + return ( + typeof arg === 'object' && + arg !== null && + arg.hasOwnProperty('hasAllPrivileges') && + typeof arg.hasAllPrivileges === 'boolean' && + arg.hasOwnProperty('missingPrivileges') && + typeof arg.missingPrivileges === 'object' && + arg.missingPrivileges !== null + ); +} + export interface MissingPrivileges { [key: string]: string[] | undefined; } export const toArray = (value: string | string[]): string[] => Array.isArray(value) ? value : [value]; -export const hasPrivilegeFactory = (privileges: Privileges) => (privilege: Privilege) => { +export const hasPrivilegeFactory = (privileges: Privileges | undefined | null) => ( + privilege: Privilege +) => { const [section, requiredPrivilege] = privilege; - if (!privileges.missingPrivileges[section]) { + if (isPrivileges(privileges) && !privileges.missingPrivileges[section]) { // if the section does not exist in our missingPrivileges, everything is OK return true; } - if (privileges.missingPrivileges[section]!.length === 0) { + if (isPrivileges(privileges) && privileges.missingPrivileges[section]!.length === 0) { return true; } if (requiredPrivilege === '*') { @@ -42,7 +56,9 @@ export const hasPrivilegeFactory = (privileges: Privileges) => (privilege: Privi } // If we require _some_ privilege, we make sure that the one // we require is *not* in the missingPrivilege array - return !privileges.missingPrivileges[section]!.includes(requiredPrivilege); + return ( + isPrivileges(privileges) && !privileges.missingPrivileges[section]!.includes(requiredPrivilege) + ); }; // create the text for button's tooltips if the user From 12f35d5788f5250803434b6d8f25d9df82ac0940 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Mon, 24 Feb 2020 10:23:44 -0800 Subject: [PATCH 026/123] Add ingest manager header component (#58300) Co-authored-by: Elastic Machine --- x-pack/legacy/plugins/ingest_manager/index.ts | 2 + .../ingest_manager/components/header.tsx | 62 ++++ .../ingest_manager/components/index.ts | 1 + .../ingest_manager/layouts/default.tsx | 29 +- .../ingest_manager/layouts/index.tsx | 1 + .../ingest_manager/layouts/with_header.tsx | 29 ++ .../sections/agent_config/list_page/index.tsx | 291 +++++++++--------- ...illustration_kibana_getting_started@2x.png | Bin 0 -> 131132 bytes .../ingest_manager/sections/epm/index.tsx | 69 ++++- .../ingest_manager/sections/fleet/index.tsx | 46 ++- .../sections/overview/index.tsx | 32 +- 11 files changed, 397 insertions(+), 165 deletions(-) create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/header.tsx create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/with_header.tsx create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/assets/illustration_kibana_getting_started@2x.png diff --git a/x-pack/legacy/plugins/ingest_manager/index.ts b/x-pack/legacy/plugins/ingest_manager/index.ts index c20cc7225d780..7ed5599b234a3 100644 --- a/x-pack/legacy/plugins/ingest_manager/index.ts +++ b/x-pack/legacy/plugins/ingest_manager/index.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { resolve } from 'path'; import { savedObjectMappings, OUTPUT_SAVED_OBJECT_TYPE, @@ -18,6 +19,7 @@ import { export function ingestManager(kibana: any) { return new kibana.Plugin({ id: 'ingestManager', + publicDir: resolve(__dirname, '../../../plugins/ingest_manager/public'), uiExports: { savedObjectSchemas: { [AGENT_CONFIG_SAVED_OBJECT_TYPE]: { diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/header.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/header.tsx new file mode 100644 index 0000000000000..0936b5dcfed10 --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/header.tsx @@ -0,0 +1,62 @@ +/* + * 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 styled from 'styled-components'; +import { EuiFlexGroup, EuiFlexItem, EuiTabs, EuiTab, EuiSpacer } from '@elastic/eui'; +import { Props as EuiTabProps } from '@elastic/eui/src/components/tabs/tab'; + +const Container = styled.div` + border-bottom: ${props => props.theme.eui.euiBorderThin}; + background-color: ${props => props.theme.eui.euiPageBackgroundColor}; +`; + +const Wrapper = styled.div` + max-width: 1200px; + margin-left: auto; + margin-right: auto; + padding-top: ${props => props.theme.eui.paddingSizes.xl}; +`; + +const Tabs = styled(EuiTabs)` + top: 1px; + &:before { + height: 0px; + } +`; + +export interface HeaderProps { + leftColumn?: JSX.Element; + rightColumn?: JSX.Element; + tabs?: EuiTabProps[]; +} + +export const Header: React.FC = ({ leftColumn, rightColumn, tabs }) => ( + + + + {leftColumn ? {leftColumn} : null} + {rightColumn ? {rightColumn} : null} + + + {tabs ? ( + + + {tabs.map(props => ( + + {props.name} + + ))} + + + ) : ( + + + + )} + + + +); diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/index.ts index 5133d82588494..b6bb29462c569 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/index.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/index.ts @@ -4,3 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ export { Loading } from './loading'; +export { Header, HeaderProps } from './header'; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx index eaf49fed3d933..f99d1bfe50026 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx @@ -4,17 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; -import { - EuiPage, - EuiPageBody, - EuiTabs, - EuiTab, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, -} from '@elastic/eui'; +import styled from 'styled-components'; +import { EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import euiStyled from '../../../../../../legacy/common/eui_styled_components'; import { Section } from '../sections'; import { useLink, useConfig } from '../hooks'; import { EPM_PATH, FLEET_PATH, AGENT_CONFIG_PATH } from '../constants'; @@ -24,7 +16,12 @@ interface Props { children?: React.ReactNode; } -const Nav = euiStyled.nav` +const Container = styled.div` + min-height: calc(100vh - ${props => props.theme.eui.euiHeaderChildSize}); + background: ${props => props.theme.eui.euiColorEmptyShade}; +`; + +const Nav = styled.nav` background: ${props => props.theme.eui.euiColorEmptyShade}; border-bottom: ${props => props.theme.eui.euiBorderThin}; padding: ${props => @@ -32,13 +29,13 @@ const Nav = euiStyled.nav` .euiTabs { padding-left: 3px; margin-left: -3px; - }; + } `; export const DefaultLayout: React.FunctionComponent = ({ section, children }) => { const { epm, fleet } = useConfig(); return ( -

+ - - {children} - -
+ {children} + ); }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/index.tsx index 858951bd0d38f..a9ef7f1656260 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/index.tsx @@ -4,3 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ export { DefaultLayout } from './default'; +export { WithHeaderLayout } from './with_header'; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/with_header.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/with_header.tsx new file mode 100644 index 0000000000000..d59c99316c8b8 --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/with_header.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, { Fragment } from 'react'; +import styled from 'styled-components'; +import { EuiPage, EuiPageBody, EuiSpacer } from '@elastic/eui'; +import { Header, HeaderProps } from '../components'; + +const Page = styled(EuiPage)` + background: ${props => props.theme.eui.euiColorEmptyShade}; +`; + +interface Props extends HeaderProps { + children?: React.ReactNode; +} + +export const WithHeaderLayout: React.FC = ({ children, ...rest }) => ( + +
+ + + + {children} + + + +); diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/list_page/index.tsx index ca9fb195166f6..ef5a38d486901 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/list_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/list_page/index.tsx @@ -5,9 +5,6 @@ */ import React, { useState } from 'react'; import { - EuiPageBody, - EuiPageContent, - EuiTitle, EuiSpacer, EuiText, EuiFlexGroup, @@ -24,11 +21,43 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { AgentConfig } from '../../../types'; import { DEFAULT_AGENT_CONFIG_ID, AGENT_CONFIG_DETAILS_PATH } from '../../../constants'; +import { WithHeaderLayout } from '../../../layouts'; // import { SearchBar } from '../../../components'; import { useGetAgentConfigs, usePagination, useLink } from '../../../hooks'; import { AgentConfigDeleteProvider } from '../components'; import { CreateAgentConfigFlyout } from './components'; +const AgentConfigListPageLayout: React.FunctionComponent = ({ children }) => ( + + + +

+ +

+
+
+ + +

+ +

+
+
+ + } + > + {children} +
+); + export const AgentConfigListPage: React.FunctionComponent<{}> = () => { // Create agent config flyout state const [isCreateAgentConfigFlyoutOpen, setIsCreateAgentConfigFlyoutOpen] = useState( @@ -123,71 +152,46 @@ export const AgentConfigListPage: React.FunctionComponent<{}> = () => { ); return ( - - - {isCreateAgentConfigFlyoutOpen ? ( - { - setIsCreateAgentConfigFlyoutOpen(false); - sendRequest(); - }} - /> - ) : null} - - -

- -

-
- - - - - - - - - - - - - - {selectedAgentConfigs.length ? ( - - - {deleteAgentConfigsPrompt => ( - { - deleteAgentConfigsPrompt( - selectedAgentConfigs.map(agentConfig => agentConfig.id), - () => { - sendRequest(); - setSelectedAgentConfigs([]); - } - ); + + {isCreateAgentConfigFlyoutOpen ? ( + { + setIsCreateAgentConfigFlyoutOpen(false); + sendRequest(); + }} + /> + ) : null} + + {selectedAgentConfigs.length ? ( + + + {deleteAgentConfigsPrompt => ( + { + deleteAgentConfigsPrompt( + selectedAgentConfigs.map(agentConfig => agentConfig.id), + () => { + sendRequest(); + setSelectedAgentConfigs([]); + } + ); + }} + > + - - - )} - - - ) : null} - - {/* + + )} + + + ) : null} + + {/* { setPagination({ @@ -198,83 +202,82 @@ export const AgentConfigListPage: React.FunctionComponent<{}> = () => { }} fieldPrefix={AGENT_CONFIG_SAVED_OBJECT_TYPE} /> */} - - - sendRequest()}> - - - - - setIsCreateAgentConfigFlyoutOpen(true)} - > - - - - + + + sendRequest()}> + + + + + setIsCreateAgentConfigFlyoutOpen(true)} + > + + + + - - - ) : !search.trim() && agentConfigData?.total === 0 ? ( - emptyPrompt - ) : ( - setSearch('')}> - - - ), - }} - /> - ) - } - items={agentConfigData ? agentConfigData.items : []} - itemId="id" - columns={columns} - isSelectable={true} - selection={{ - selectable: (agentConfig: AgentConfig) => agentConfig.id !== DEFAULT_AGENT_CONFIG_ID, - onSelectionChange: (newSelectedAgentConfigs: AgentConfig[]) => { - setSelectedAgentConfigs(newSelectedAgentConfigs); - }, - }} - pagination={{ - pageIndex: pagination.currentPage - 1, - pageSize: pagination.pageSize, - totalItemCount: agentConfigData ? agentConfigData.total : 0, - }} - onChange={({ page }: { page: { index: number; size: number } }) => { - const newPagination = { - ...pagination, - currentPage: page.index + 1, - pageSize: page.size, - }; - setPagination(newPagination); - sendRequest(); // todo: fix this to send pagination options - }} - /> -
-
+ + + ) : !search.trim() && agentConfigData?.total === 0 ? ( + emptyPrompt + ) : ( + setSearch('')}> + + + ), + }} + /> + ) + } + items={agentConfigData ? agentConfigData.items : []} + itemId="id" + columns={columns} + isSelectable={true} + selection={{ + selectable: (agentConfig: AgentConfig) => agentConfig.id !== DEFAULT_AGENT_CONFIG_ID, + onSelectionChange: (newSelectedAgentConfigs: AgentConfig[]) => { + setSelectedAgentConfigs(newSelectedAgentConfigs); + }, + }} + pagination={{ + pageIndex: pagination.currentPage - 1, + pageSize: pagination.pageSize, + totalItemCount: agentConfigData ? agentConfigData.total : 0, + }} + onChange={({ page }: { page: { index: number; size: number } }) => { + const newPagination = { + ...pagination, + currentPage: page.index + 1, + pageSize: page.size, + }; + setPagination(newPagination); + sendRequest(); // todo: fix this to send pagination options + }} + /> + ); }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/assets/illustration_kibana_getting_started@2x.png b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/assets/illustration_kibana_getting_started@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cad64be0b6e36e79012970814c7018776bee5f73 GIT binary patch literal 131132 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ͤum)*z|9JCu4oQ+`+gia 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 { const { epm } = useConfig(); - return epm.enabled ?
hello world - epm app
: null; + const { http } = useCore(); + + if (!epm.enabled) { + return null; + } + + return ( + + + +

+ +

+
+
+ + +

+ +

+
+
+ + } + rightColumn={ + + + + } + tabs={[ + { + id: 'all_packages', + name: 'All packages', + isSelected: true, + }, + { + id: 'installed_packages', + name: 'Installed packages', + }, + ]} + > + hello world - fleet app +
+ ); }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/index.tsx index 978414769004d..c4e8c576a1d7d 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/index.tsx @@ -4,9 +4,53 @@ * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { WithHeaderLayout } from '../../layouts'; import { useConfig } from '../../hooks'; export const FleetApp: React.FunctionComponent = () => { const { fleet } = useConfig(); - return fleet.enabled ?
hello world - fleet app
: null; + if (!fleet.enabled) { + return null; + } + + return ( + + + +

+ +

+
+
+ + +

+ +

+
+
+ + } + tabs={[ + { + id: 'agents', + name: 'Agents', + isSelected: true, + }, + { + id: 'enrollment_keys', + name: 'Enrollment keys', + }, + ]} + > + hello world - fleet app +
+ ); }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/index.tsx index da4a78a39e2fe..ea6b045f504ec 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/index.tsx @@ -4,7 +4,37 @@ * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; +import { EuiText, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { WithHeaderLayout } from '../../layouts'; export const IngestManagerOverview: React.FunctionComponent = () => { - return
Ingest manager overview page
; + return ( + + + +

+ +

+
+
+ + +

+ +

+
+
+ + } + /> + ); }; From 63d5e382d888728f6a96eede327c61eaae271989 Mon Sep 17 00:00:00 2001 From: Peter Pisljar Date: Mon, 24 Feb 2020 13:40:33 -0500 Subject: [PATCH 027/123] removes extraHandlers (#58336) --- .../public/embeddable/visualize_embeddable.ts | 4 +--- src/plugins/expressions/public/loader.ts | 6 +++--- src/plugins/expressions/public/render.ts | 4 ++-- src/plugins/expressions/public/types/index.ts | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts index 72a0ef72b5693..32bbae13b79b8 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -369,9 +369,7 @@ export class VisualizeEmbeddable extends Embeddable { + render = async (data: any, uiState: any = {}) => { if (!data || typeof data !== 'object') { return this.handleRenderError(new Error('invalid data provided to the expression renderer')); } @@ -119,7 +119,7 @@ export class ExpressionRenderHandler { .get(data.as)! .render(this.element, data.value, { ...this.handlers, - ...extraHandlers, + uiState, } as any); } catch (e) { return this.handleRenderError(e); diff --git a/src/plugins/expressions/public/types/index.ts b/src/plugins/expressions/public/types/index.ts index c77698d3661c2..b5781ef213fd0 100644 --- a/src/plugins/expressions/public/types/index.ts +++ b/src/plugins/expressions/public/types/index.ts @@ -48,7 +48,7 @@ export interface IExpressionLoaderParams { disableCaching?: boolean; customFunctions?: []; customRenderers?: []; - extraHandlers?: Record; + uiState?: unknown; inspectorAdapters?: Adapters; onRenderError?: RenderErrorHandlerFnType; } From d1df0e5da5a642b889bbe626a5ebaad8bf973f9a Mon Sep 17 00:00:00 2001 From: Ahmad Bamieh Date: Mon, 24 Feb 2020 20:47:32 +0200 Subject: [PATCH 028/123] [Telemetry] Server backpressure mechanism (#57556) * finish backpressure mechanism * usage fetch method send OPTIONS before sending POST * add unit test for get_telemetry_failure_details * get currentVersion in constructor * fix type check Co-authored-by: Elastic Machine --- .../core_plugins/telemetry/mappings.json | 7 ++ .../core_plugins/telemetry/server/fetcher.ts | 68 ++++++++++--- .../get_telemetry_failure_details.test.ts | 96 +++++++++++++++++++ .../get_telemetry_failure_details.ts | 45 +++++++++ .../server/telemetry_config/index.ts | 4 + .../server/telemetry_repository/index.ts | 2 + src/plugins/telemetry/public/plugin.ts | 12 +-- 7 files changed, 215 insertions(+), 19 deletions(-) create mode 100644 src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_failure_details.test.ts create mode 100644 src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_failure_details.ts diff --git a/src/legacy/core_plugins/telemetry/mappings.json b/src/legacy/core_plugins/telemetry/mappings.json index a88372a5578e8..fa9cc93d6363a 100644 --- a/src/legacy/core_plugins/telemetry/mappings.json +++ b/src/legacy/core_plugins/telemetry/mappings.json @@ -17,6 +17,13 @@ }, "userHasSeenNotice": { "type": "boolean" + }, + "reportFailureCount": { + "type": "integer" + }, + "reportFailureVersion": { + "ignore_above": 256, + "type": "keyword" } } } diff --git a/src/legacy/core_plugins/telemetry/server/fetcher.ts b/src/legacy/core_plugins/telemetry/server/fetcher.ts index 6e16328c4abd8..d30ee10066813 100644 --- a/src/legacy/core_plugins/telemetry/server/fetcher.ts +++ b/src/legacy/core_plugins/telemetry/server/fetcher.ts @@ -21,19 +21,26 @@ import moment from 'moment'; // @ts-ignore import fetch from 'node-fetch'; import { telemetryCollectionManager } from './collection_manager'; -import { getTelemetryOptIn, getTelemetrySendUsageFrom } from './telemetry_config'; +import { + getTelemetryOptIn, + getTelemetrySendUsageFrom, + getTelemetryFailureDetails, +} from './telemetry_config'; import { getTelemetrySavedObject, updateTelemetrySavedObject } from './telemetry_repository'; import { REPORT_INTERVAL_MS } from '../common/constants'; export class FetcherTask { - private readonly checkDurationMs = 60 * 1000 * 5; + private readonly initialCheckDelayMs = 60 * 1000 * 5; + private readonly checkIntervalMs = 60 * 1000 * 60 * 12; private intervalId?: NodeJS.Timeout; private lastReported?: number; + private currentVersion: string; private isSending = false; private server: any; constructor(server: any) { this.server = server; + this.currentVersion = this.server.config().get('pkg.version'); } private getInternalRepository = () => { @@ -52,6 +59,9 @@ export class FetcherTask { const allowChangingOptInStatus = config.get('telemetry.allowChangingOptInStatus'); const configTelemetryOptIn = config.get('telemetry.optIn'); const telemetryUrl = config.get('telemetry.url') as string; + const { failureCount, failureVersion } = await getTelemetryFailureDetails({ + telemetrySavedObject, + }); return { telemetryOptIn: getTelemetryOptIn({ @@ -65,6 +75,8 @@ export class FetcherTask { configTelemetrySendUsageFrom, }), telemetryUrl, + failureCount, + failureVersion, }; }; @@ -72,11 +84,31 @@ export class FetcherTask { const internalRepository = this.getInternalRepository(); this.lastReported = Date.now(); updateTelemetrySavedObject(internalRepository, { + reportFailureCount: 0, lastReported: this.lastReported, }); }; - private shouldSendReport = ({ telemetryOptIn, telemetrySendUsageFrom }: any) => { + private updateReportFailure = async ({ failureCount }: { failureCount: number }) => { + const internalRepository = this.getInternalRepository(); + + updateTelemetrySavedObject(internalRepository, { + reportFailureCount: failureCount + 1, + reportFailureVersion: this.currentVersion, + }); + }; + + private shouldSendReport = ({ + telemetryOptIn, + telemetrySendUsageFrom, + reportFailureCount, + currentVersion, + reportFailureVersion, + }: any) => { + if (reportFailureCount > 2 && reportFailureVersion === currentVersion) { + return false; + } + if (telemetryOptIn && telemetrySendUsageFrom === 'server') { if (!this.lastReported || Date.now() - this.lastReported > REPORT_INTERVAL_MS) { return true; @@ -98,6 +130,14 @@ export class FetcherTask { private sendTelemetry = async (url: string, cluster: any): Promise => { this.server.log(['debug', 'telemetry', 'fetcher'], `Sending usage stats.`); + /** + * send OPTIONS before sending usage data. + * OPTIONS is less intrusive as it does not contain any payload and is used here to check if the endpoint is reachable. + */ + await fetch(url, { + method: 'options', + }); + await fetch(url, { method: 'post', body: cluster, @@ -108,21 +148,23 @@ export class FetcherTask { if (this.isSending) { return; } - try { - const telemetryConfig = await this.getCurrentConfigs(); - if (!this.shouldSendReport(telemetryConfig)) { - return; - } + const telemetryConfig = await this.getCurrentConfigs(); + if (!this.shouldSendReport(telemetryConfig)) { + return; + } - // mark that we are working so future requests are ignored until we're done + try { this.isSending = true; const clusters = await this.fetchTelemetry(); + const { telemetryUrl } = telemetryConfig; for (const cluster of clusters) { - await this.sendTelemetry(telemetryConfig.telemetryUrl, cluster); + await this.sendTelemetry(telemetryUrl, cluster); } await this.updateLastReported(); } catch (err) { + await this.updateReportFailure(telemetryConfig); + this.server.log( ['warning', 'telemetry', 'fetcher'], `Error sending telemetry usage data: ${err}` @@ -132,8 +174,12 @@ export class FetcherTask { }; public start = () => { - this.intervalId = setInterval(() => this.sendIfDue(), this.checkDurationMs); + setTimeout(() => { + this.sendIfDue(); + this.intervalId = setInterval(() => this.sendIfDue(), this.checkIntervalMs); + }, this.initialCheckDelayMs); }; + public stop = () => { if (this.intervalId) { clearInterval(this.intervalId); diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_failure_details.test.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_failure_details.test.ts new file mode 100644 index 0000000000000..c92696838e8e8 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_failure_details.test.ts @@ -0,0 +1,96 @@ +/* + * 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 { getTelemetryFailureDetails } from './get_telemetry_failure_details'; + +describe('getTelemetryFailureDetails: get details about server usage fetcher failures', () => { + it('returns `failureCount: 0` and `failureVersion: undefined` when telemetry does not have any custom configs in saved Object', () => { + const telemetrySavedObject = null; + const failureDetails = getTelemetryFailureDetails({ telemetrySavedObject }); + expect(failureDetails).toStrictEqual({ + failureVersion: undefined, + failureCount: 0, + }); + }); + + it('returns telemetryFailureCount and reportFailureVersion from telemetry saved Object', () => { + const telemetrySavedObject = { + reportFailureCount: 12, + reportFailureVersion: '8.0.0', + }; + const failureDetails = getTelemetryFailureDetails({ telemetrySavedObject }); + expect(failureDetails).toStrictEqual({ + failureVersion: '8.0.0', + failureCount: 12, + }); + }); + + it('returns `failureCount: 0` on malformed reportFailureCount telemetry saved Object', () => { + const failureVersion = '8.0.0'; + expect( + getTelemetryFailureDetails({ + telemetrySavedObject: { + reportFailureCount: null, + reportFailureVersion: failureVersion, + } as any, + }) + ).toStrictEqual({ failureVersion, failureCount: 0 }); + expect( + getTelemetryFailureDetails({ + telemetrySavedObject: { + reportFailureCount: undefined, + reportFailureVersion: failureVersion, + }, + }) + ).toStrictEqual({ failureVersion, failureCount: 0 }); + expect( + getTelemetryFailureDetails({ + telemetrySavedObject: { + reportFailureCount: 'not_a_number', + reportFailureVersion: failureVersion, + } as any, + }) + ).toStrictEqual({ failureVersion, failureCount: 0 }); + }); + + it('returns `failureVersion: undefined` on malformed reportFailureCount telemetry saved Object', () => { + const failureCount = 0; + expect( + getTelemetryFailureDetails({ + telemetrySavedObject: { + reportFailureVersion: null, + reportFailureCount: failureCount, + } as any, + }) + ).toStrictEqual({ failureCount, failureVersion: undefined }); + expect( + getTelemetryFailureDetails({ + telemetrySavedObject: { reportFailureVersion: undefined, reportFailureCount: failureCount }, + }) + ).toStrictEqual({ failureCount, failureVersion: undefined }); + expect( + getTelemetryFailureDetails({ + telemetrySavedObject: { + reportFailureVersion: 123, + reportFailureCount: failureCount, + } as any, + }) + ).toStrictEqual({ failureCount, failureVersion: undefined }); + }); +}); diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_failure_details.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_failure_details.ts new file mode 100644 index 0000000000000..2952fa96a5cf3 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_failure_details.ts @@ -0,0 +1,45 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { TelemetrySavedObject } from '../telemetry_repository/get_telemetry_saved_object'; + +interface GetTelemetryFailureDetailsConfig { + telemetrySavedObject: TelemetrySavedObject; +} + +export interface TelemetryFailureDetails { + failureCount: number; + failureVersion?: string; +} + +export function getTelemetryFailureDetails({ + telemetrySavedObject, +}: GetTelemetryFailureDetailsConfig): TelemetryFailureDetails { + if (!telemetrySavedObject) { + return { + failureVersion: undefined, + failureCount: 0, + }; + } + const { reportFailureCount, reportFailureVersion } = telemetrySavedObject; + + return { + failureCount: typeof reportFailureCount === 'number' ? reportFailureCount : 0, + failureVersion: typeof reportFailureVersion === 'string' ? reportFailureVersion : undefined, + }; +} diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_config/index.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/index.ts index ab30dac1c3666..bf9855ce7538e 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_config/index.ts +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/index.ts @@ -21,3 +21,7 @@ export { replaceTelemetryInjectedVars } from './replace_injected_vars'; export { getTelemetryOptIn } from './get_telemetry_opt_in'; export { getTelemetrySendUsageFrom } from './get_telemetry_send_usage_from'; export { getTelemetryAllowChangingOptInStatus } from './get_telemetry_allow_changing_opt_in_status'; +export { + getTelemetryFailureDetails, + TelemetryFailureDetails, +} from './get_telemetry_failure_details'; diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_repository/index.ts b/src/legacy/core_plugins/telemetry/server/telemetry_repository/index.ts index b9ba2ce5573c3..f1735d1bb2866 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_repository/index.ts +++ b/src/legacy/core_plugins/telemetry/server/telemetry_repository/index.ts @@ -27,4 +27,6 @@ export interface TelemetrySavedObjectAttributes { lastReported?: number; telemetryAllowChangingOptInStatus?: boolean; userHasSeenNotice?: boolean; + reportFailureCount?: number; + reportFailureVersion?: string; } diff --git a/src/plugins/telemetry/public/plugin.ts b/src/plugins/telemetry/public/plugin.ts index 7ba51cacd1949..9cfb4ca1ec395 100644 --- a/src/plugins/telemetry/public/plugin.ts +++ b/src/plugins/telemetry/public/plugin.ts @@ -54,9 +54,6 @@ export class TelemetryPlugin implements Plugin Date: Mon, 24 Feb 2020 13:24:46 -0600 Subject: [PATCH 029/123] Show blank lines instead of N/A on service map popovers (#57014) * Show blank lines instead of N/A on service map popovers Because RUM agents never show CPU or memory usage, we don't want to always show the metric with N/A. If a metric is null, just hide the lines. Break up the display and fetching components and update the popover stories to show the list. Update some types. * Fix metric typings --- .../app/ServiceMap/Popover/Contents.tsx | 4 +- .../ServiceMap/Popover/Popover.stories.tsx | 86 +++++++++-------- .../Popover/ServiceMetricFetcher.tsx | 41 +++++++++ .../ServiceMap/Popover/ServiceMetricList.tsx | 92 ++++++------------- x-pack/plugins/apm/common/service_map.ts | 9 ++ .../get_service_map_service_node_info.ts | 31 ++++--- 6 files changed, 147 insertions(+), 116 deletions(-) create mode 100644 x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx index 378ad9509c217..f1c53673c8755 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx @@ -14,7 +14,7 @@ import cytoscape from 'cytoscape'; import React from 'react'; import { Buttons } from './Buttons'; import { Info } from './Info'; -import { ServiceMetricList } from './ServiceMetricList'; +import { ServiceMetricFetcher } from './ServiceMetricFetcher'; const popoverMinWidth = 280; @@ -49,7 +49,7 @@ export function Contents({ {isService ? ( - + ) : ( )} diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx index b26488c5ef7de..e5962afd76eb8 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx @@ -6,44 +6,50 @@ import { storiesOf } from '@storybook/react'; import React from 'react'; -import { - ApmPluginContext, - ApmPluginContextValue -} from '../../../../context/ApmPluginContext'; -import { Contents } from './Contents'; +import { ServiceMetricList } from './ServiceMetricList'; -const selectedNodeData = { - id: 'opbeans-node', - label: 'opbeans-node', - href: - '#/services/opbeans-node/service-map?rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0', - agentName: 'nodejs', - type: 'service' -}; - -storiesOf('app/ServiceMap/Popover/Contents', module).add( - 'example', - () => { - return ( - - {}} - selectedNodeServiceName="opbeans-node" - /> - - ); - }, - { - info: { - propTablesExclude: [ApmPluginContext.Provider], - source: false - } - } -); +storiesOf('app/ServiceMap/Popover/ServiceMetricList', module) + .add('example', () => ( + + )) + .add('loading', () => ( + + )) + .add('some null values', () => ( + + )) + .add('all null values', () => ( + + )); diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx new file mode 100644 index 0000000000000..b0a5e892b5a7e --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { ServiceNodeMetrics } from '../../../../../../../../plugins/apm/common/service_map'; +import { useFetcher } from '../../../../hooks/useFetcher'; +import { useUrlParams } from '../../../../hooks/useUrlParams'; +import { ServiceMetricList } from './ServiceMetricList'; + +interface ServiceMetricFetcherProps { + serviceName: string; +} + +export function ServiceMetricFetcher({ + serviceName +}: ServiceMetricFetcherProps) { + const { + urlParams: { start, end, environment } + } = useUrlParams(); + + const { data = {} as ServiceNodeMetrics, status } = useFetcher( + callApmApi => { + if (serviceName && start && end) { + return callApmApi({ + pathname: '/api/apm/service-map/service/{serviceName}', + params: { path: { serviceName }, query: { start, end, environment } } + }); + } + }, + [serviceName, start, end, environment], + { + preservePreviousData: false + } + ); + const isLoading = status === 'loading'; + + return ; +} diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx index e91eb5e006d82..50ce918ea7037 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx @@ -5,26 +5,23 @@ */ import { + EuiBadge, EuiFlexGroup, - EuiLoadingSpinner, EuiFlexItem, - EuiBadge + EuiLoadingSpinner } from '@elastic/eui'; import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; import { isNumber } from 'lodash'; import React from 'react'; import styled from 'styled-components'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ServiceNodeMetrics } from '../../../../../../../../plugins/apm/server/lib/service_map/get_service_map_service_node_info'; +import { ServiceNodeMetrics } from '../../../../../../../../plugins/apm/common/service_map'; import { asDuration, asPercent, toMicroseconds, tpmUnit } from '../../../../utils/formatters'; -import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { useFetcher } from '../../../../hooks/useFetcher'; function LoadingSpinner() { return ( @@ -51,53 +48,19 @@ const ItemDescription = styled('td')` text-align: right; `; -const na = i18n.translate('xpack.apm.serviceMap.NotAvailableMetric', { - defaultMessage: 'N/A' -}); - -interface MetricListProps { - serviceName: string; +interface ServiceMetricListProps extends ServiceNodeMetrics { + isLoading: boolean; } -export function ServiceMetricList({ serviceName }: MetricListProps) { - const { - urlParams: { start, end, environment } - } = useUrlParams(); - - const { data = {} as ServiceNodeMetrics, status } = useFetcher( - callApmApi => { - if (serviceName && start && end) { - return callApmApi({ - pathname: '/api/apm/service-map/service/{serviceName}', - params: { - path: { - serviceName - }, - query: { - start, - end, - environment - } - } - }); - } - }, - [serviceName, start, end, environment], - { - preservePreviousData: false - } - ); - - const { - avgTransactionDuration, - avgRequestsPerMinute, - avgErrorsPerMinute, - avgCpuUsage, - avgMemoryUsage, - numInstances - } = data; - const isLoading = status === 'loading'; - +export function ServiceMetricList({ + avgTransactionDuration, + avgRequestsPerMinute, + avgErrorsPerMinute, + avgCpuUsage, + avgMemoryUsage, + numInstances, + isLoading +}: ServiceMetricListProps) { const listItems = [ { title: i18n.translate( @@ -108,7 +71,7 @@ export function ServiceMetricList({ serviceName }: MetricListProps) { ), description: isNumber(avgTransactionDuration) ? asDuration(toMicroseconds(avgTransactionDuration, 'milliseconds')) - : na + : null }, { title: i18n.translate( @@ -119,7 +82,7 @@ export function ServiceMetricList({ serviceName }: MetricListProps) { ), description: isNumber(avgRequestsPerMinute) ? `${avgRequestsPerMinute.toFixed(2)} ${tpmUnit('request')}` - : na + : null }, { title: i18n.translate( @@ -128,13 +91,13 @@ export function ServiceMetricList({ serviceName }: MetricListProps) { defaultMessage: 'Errors per minute (avg.)' } ), - description: avgErrorsPerMinute?.toFixed(2) ?? na + description: avgErrorsPerMinute?.toFixed(2) }, { title: i18n.translate('xpack.apm.serviceMap.avgCpuUsagePopoverMetric', { defaultMessage: 'CPU usage (avg.)' }), - description: isNumber(avgCpuUsage) ? asPercent(avgCpuUsage, 1) : na + description: isNumber(avgCpuUsage) ? asPercent(avgCpuUsage, 1) : null }, { title: i18n.translate( @@ -143,7 +106,9 @@ export function ServiceMetricList({ serviceName }: MetricListProps) { defaultMessage: 'Memory usage (avg.)' } ), - description: isNumber(avgMemoryUsage) ? asPercent(avgMemoryUsage, 1) : na + description: isNumber(avgMemoryUsage) + ? asPercent(avgMemoryUsage, 1) + : null } ]; return isLoading ? ( @@ -165,12 +130,15 @@ export function ServiceMetricList({ serviceName }: MetricListProps) { - {listItems.map(({ title, description }) => ( - - {title} - {description} - - ))} + {listItems.map( + ({ title, description }) => + description && ( + + {title} + {description} + + ) + )}
diff --git a/x-pack/plugins/apm/common/service_map.ts b/x-pack/plugins/apm/common/service_map.ts index fbaa489c45039..528aec2f70ad9 100644 --- a/x-pack/plugins/apm/common/service_map.ts +++ b/x-pack/plugins/apm/common/service_map.ts @@ -21,3 +21,12 @@ export interface Connection { source: ConnectionNode; destination: ConnectionNode; } + +export interface ServiceNodeMetrics { + numInstances: number; + avgMemoryUsage: number | null; + avgCpuUsage: number | null; + avgTransactionDuration: number | null; + avgRequestsPerMinute: number | null; + avgErrorsPerMinute: number | null; +} diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts index 6c4d540103cec..0fe825e8ace35 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts @@ -18,7 +18,6 @@ import { SERVICE_NODE_NAME } from '../../../common/elasticsearch_fieldnames'; import { percentMemoryUsedScript } from '../metrics/by_agent/shared/memory'; -import { PromiseReturnType } from '../../../typings/common'; interface Options { setup: Setup & SetupTimeRange; @@ -32,10 +31,6 @@ interface TaskParameters { filter: ESFilter[]; } -export type ServiceNodeMetrics = PromiseReturnType< - typeof getServiceMapServiceNodeInfo ->; - export async function getServiceMapServiceNodeInfo({ serviceName, environment, @@ -112,7 +107,10 @@ async function getTransactionMetrics({ setup, filter, minutes -}: TaskParameters) { +}: TaskParameters): Promise<{ + avgTransactionDuration: number | null; + avgRequestsPerMinute: number | null; +}> { const { indices, client } = setup; const response = await client.search({ @@ -140,13 +138,16 @@ async function getTransactionMetrics({ }); return { - avgTransactionDuration: response.aggregations?.duration.value, + avgTransactionDuration: response.aggregations?.duration.value ?? null, avgRequestsPerMinute: response.hits.total.value > 0 ? response.hits.total.value / minutes : null }; } -async function getCpuMetrics({ setup, filter }: TaskParameters) { +async function getCpuMetrics({ + setup, + filter +}: TaskParameters): Promise<{ avgCpuUsage: number | null }> { const { indices, client } = setup; const response = await client.search({ @@ -180,11 +181,14 @@ async function getCpuMetrics({ setup, filter }: TaskParameters) { }); return { - avgCpuUsage: response.aggregations?.avgCpuUsage.value + avgCpuUsage: response.aggregations?.avgCpuUsage.value ?? null }; } -async function getMemoryMetrics({ setup, filter }: TaskParameters) { +async function getMemoryMetrics({ + setup, + filter +}: TaskParameters): Promise<{ avgMemoryUsage: number | null }> { const { client, indices } = setup; const response = await client.search({ index: indices['apm_oss.metricsIndices'], @@ -221,11 +225,14 @@ async function getMemoryMetrics({ setup, filter }: TaskParameters) { }); return { - avgMemoryUsage: response.aggregations?.avgMemoryUsage.value + avgMemoryUsage: response.aggregations?.avgMemoryUsage.value ?? null }; } -async function getNumInstances({ setup, filter }: TaskParameters) { +async function getNumInstances({ + setup, + filter +}: TaskParameters): Promise<{ numInstances: number }> { const { client, indices } = setup; const response = await client.search({ index: indices['apm_oss.transactionIndices'], From 858fe2e9251e748bfbcd85623f22d9c1eac71076 Mon Sep 17 00:00:00 2001 From: Maggie Ghamry <46542915+maggieghamry@users.noreply.github.com> Date: Mon, 24 Feb 2020 14:44:19 -0500 Subject: [PATCH 030/123] [Canvas] Toggles footer editable controls when you turn off edit mode #52786 (#58044) * Bug fix update update to toggle footer edit controls "off" when locking edit controls. * Update to toggle Update to toggle, so that only the "Expression Editor" and tray are hidden when locking controls. * Update to toggle logic Added canUserWrite property, and added a condition to ensure the "page" tray still shows once the Expression editor is locked * Update to property definition Update to consolidate isWriteable and canUserWrite into one variable instead of two. * Adding Test (in progress) code Adding Toolbar test code (so far) - needs to be completed to address nested compononet storybook issue * Adding issue link Adding issue link in TODO comments Co-authored-by: Elastic Machine --- .../toolbar/__examples__/toolbar.stories.tsx | 39 +++++++++++++++++++ .../canvas/public/components/toolbar/index.js | 3 ++ .../public/components/toolbar/toolbar.tsx | 11 +++++- 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 x-pack/legacy/plugins/canvas/public/components/toolbar/__examples__/toolbar.stories.tsx diff --git a/x-pack/legacy/plugins/canvas/public/components/toolbar/__examples__/toolbar.stories.tsx b/x-pack/legacy/plugins/canvas/public/components/toolbar/__examples__/toolbar.stories.tsx new file mode 100644 index 0000000000000..5907c932ddabb --- /dev/null +++ b/x-pack/legacy/plugins/canvas/public/components/toolbar/__examples__/toolbar.stories.tsx @@ -0,0 +1,39 @@ +/* + * 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. + */ + +/* + TODO: uncomment and fix this test to address storybook errors as a result of nested component dependencies - https://github.com/elastic/kibana/issues/58289 + */ + +/* +import { action } from '@storybook/addon-actions'; +import { storiesOf } from '@storybook/react'; +import React from 'react'; +import { Toolbar } from '../toolbar'; + +storiesOf('components/Toolbar', module) + .addDecorator(story => ( +
+ {story()} +
+ )) + .add('with null metric', () => ( + + )); +*/ diff --git a/x-pack/legacy/plugins/canvas/public/components/toolbar/index.js b/x-pack/legacy/plugins/canvas/public/components/toolbar/index.js index c834304739a4c..294a44ba0415a 100644 --- a/x-pack/legacy/plugins/canvas/public/components/toolbar/index.js +++ b/x-pack/legacy/plugins/canvas/public/components/toolbar/index.js @@ -7,12 +7,14 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import { pure, compose, withState, getContext, withHandlers } from 'recompose'; +import { canUserWrite } from '../../state/selectors/app'; import { getWorkpad, getWorkpadName, getSelectedPageIndex, getSelectedElement, + isWriteable, } from '../../state/selectors/workpad'; import { Toolbar as Component } from './toolbar'; @@ -23,6 +25,7 @@ const mapStateToProps = state => ({ totalPages: getWorkpad(state).pages.length, selectedPageNumber: getSelectedPageIndex(state) + 1, selectedElement: getSelectedElement(state), + isWriteable: isWriteable(state) && canUserWrite(state), }); export const Toolbar = compose( diff --git a/x-pack/legacy/plugins/canvas/public/components/toolbar/toolbar.tsx b/x-pack/legacy/plugins/canvas/public/components/toolbar/toolbar.tsx index 089f021ccdc32..0f8204e6bc261 100644 --- a/x-pack/legacy/plugins/canvas/public/components/toolbar/toolbar.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/toolbar/toolbar.tsx @@ -39,7 +39,8 @@ enum TrayType { interface Props { workpadName: string; - + isWriteable: boolean; + canUserWrite: boolean; tray: TrayType | null; setTray: (tray: TrayType | null) => void; @@ -66,12 +67,17 @@ export const Toolbar = (props: Props) => { totalPages, showWorkpadManager, setShowWorkpadManager, + isWriteable, } = props; const elementIsSelected = Boolean(selectedElement); const done = () => setTray(null); + if (!isWriteable && tray === TrayType.expression) { + done(); + } + const showHideTray = (exp: TrayType) => { if (tray && tray === exp) { return done(); @@ -135,7 +141,7 @@ export const Toolbar = (props: Props) => { />
- {elementIsSelected && ( + {elementIsSelected && isWriteable && ( Date: Mon, 24 Feb 2020 20:09:38 +0000 Subject: [PATCH 031/123] chore(NA): remove empty filter check from thread loader pool config getter (#58385) --- src/optimize/base_optimizer.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/optimize/base_optimizer.js b/src/optimize/base_optimizer.js index a833204eaa0e2..a94f251c292f9 100644 --- a/src/optimize/base_optimizer.js +++ b/src/optimize/base_optimizer.js @@ -152,11 +152,7 @@ export default class BaseOptimizer { getThreadLoaderPoolConfig() { // Calculate the node options from the NODE_OPTIONS env var - const parsedNodeOptions = process.env.NODE_OPTIONS - ? // thread-loader could not receive empty string as options - // or it would break that's why we need to filter here - process.env.NODE_OPTIONS.split(/\s/).filter(opt => !!opt) - : []; + const parsedNodeOptions = process.env.NODE_OPTIONS ? process.env.NODE_OPTIONS.split(/\s/) : []; return { name: 'optimizer-thread-loader-main-pool', From 77fe83e7db27b410cd1eb63084c22ca7bb32d278 Mon Sep 17 00:00:00 2001 From: Brandon Kobel Date: Mon, 24 Feb 2020 13:04:30 -0800 Subject: [PATCH 032/123] Remove restriction that route must start with `/api` to use api authorization (#58351) Co-authored-by: Elastic Machine --- .../authorization/api_authorization.test.ts | 36 +++++-------------- .../server/authorization/api_authorization.ts | 4 +-- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/x-pack/plugins/security/server/authorization/api_authorization.test.ts b/x-pack/plugins/security/server/authorization/api_authorization.test.ts index a5902f251b082..409f998cfe8d2 100644 --- a/x-pack/plugins/security/server/authorization/api_authorization.test.ts +++ b/x-pack/plugins/security/server/authorization/api_authorization.test.ts @@ -15,27 +15,7 @@ import { import { authorizationMock } from './index.mock'; describe('initAPIAuthorization', () => { - test(`route that doesn't start with "/api/" continues`, async () => { - const mockHTTPSetup = coreMock.createSetup().http; - initAPIAuthorization( - mockHTTPSetup, - authorizationMock.create(), - loggingServiceMock.create().get() - ); - - const [[postAuthHandler]] = mockHTTPSetup.registerOnPostAuth.mock.calls; - - const mockRequest = httpServerMock.createKibanaRequest({ method: 'get', path: '/app/foo' }); - const mockResponse = httpServerMock.createResponseFactory(); - const mockPostAuthToolkit = httpServiceMock.createOnPostAuthToolkit(); - - await postAuthHandler(mockRequest, mockResponse, mockPostAuthToolkit); - - expect(mockResponse.notFound).not.toHaveBeenCalled(); - expect(mockPostAuthToolkit.next).toHaveBeenCalledTimes(1); - }); - - test(`protected route that starts with "/api/", but "mode.useRbacForRequest()" returns false continues`, async () => { + test(`protected route when "mode.useRbacForRequest()" returns false continues`, async () => { const mockHTTPSetup = coreMock.createSetup().http; const mockAuthz = authorizationMock.create(); initAPIAuthorization(mockHTTPSetup, mockAuthz, loggingServiceMock.create().get()); @@ -44,7 +24,7 @@ describe('initAPIAuthorization', () => { const mockRequest = httpServerMock.createKibanaRequest({ method: 'get', - path: '/api/foo', + path: '/foo/bar', routeTags: ['access:foo'], }); const mockResponse = httpServerMock.createResponseFactory(); @@ -59,7 +39,7 @@ describe('initAPIAuthorization', () => { expect(mockAuthz.mode.useRbacForRequest).toHaveBeenCalledWith(mockRequest); }); - test(`unprotected route that starts with "/api/", but "mode.useRbacForRequest()" returns true continues`, async () => { + test(`unprotected route when "mode.useRbacForRequest()" returns true continues`, async () => { const mockHTTPSetup = coreMock.createSetup().http; const mockAuthz = authorizationMock.create(); initAPIAuthorization(mockHTTPSetup, mockAuthz, loggingServiceMock.create().get()); @@ -68,7 +48,7 @@ describe('initAPIAuthorization', () => { const mockRequest = httpServerMock.createKibanaRequest({ method: 'get', - path: '/api/foo', + path: '/foo/bar', routeTags: ['not-access:foo'], }); const mockResponse = httpServerMock.createResponseFactory(); @@ -83,7 +63,7 @@ describe('initAPIAuthorization', () => { expect(mockAuthz.mode.useRbacForRequest).toHaveBeenCalledWith(mockRequest); }); - test(`protected route that starts with "/api/", "mode.useRbacForRequest()" returns true and user is authorized continues`, async () => { + test(`protected route when "mode.useRbacForRequest()" returns true and user is authorized continues`, async () => { const mockHTTPSetup = coreMock.createSetup().http; const mockAuthz = authorizationMock.create({ version: '1.0.0-zeta1' }); initAPIAuthorization(mockHTTPSetup, mockAuthz, loggingServiceMock.create().get()); @@ -93,7 +73,7 @@ describe('initAPIAuthorization', () => { const headers = { authorization: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ method: 'get', - path: '/api/foo', + path: '/foo/bar', headers, routeTags: ['access:foo'], }); @@ -118,7 +98,7 @@ describe('initAPIAuthorization', () => { expect(mockAuthz.mode.useRbacForRequest).toHaveBeenCalledWith(mockRequest); }); - test(`protected route that starts with "/api/", "mode.useRbacForRequest()" returns true and user isn't authorized responds with a 404`, async () => { + test(`protected route when "mode.useRbacForRequest()" returns true and user isn't authorized responds with a 404`, async () => { const mockHTTPSetup = coreMock.createSetup().http; const mockAuthz = authorizationMock.create({ version: '1.0.0-zeta1' }); initAPIAuthorization(mockHTTPSetup, mockAuthz, loggingServiceMock.create().get()); @@ -128,7 +108,7 @@ describe('initAPIAuthorization', () => { const headers = { authorization: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ method: 'get', - path: '/api/foo', + path: '/foo/bar', headers, routeTags: ['access:foo'], }); diff --git a/x-pack/plugins/security/server/authorization/api_authorization.ts b/x-pack/plugins/security/server/authorization/api_authorization.ts index b280cc74c230f..cc672fbc69e06 100644 --- a/x-pack/plugins/security/server/authorization/api_authorization.ts +++ b/x-pack/plugins/security/server/authorization/api_authorization.ts @@ -13,8 +13,8 @@ export function initAPIAuthorization( logger: Logger ) { http.registerOnPostAuth(async (request, response, toolkit) => { - // if the api doesn't start with "/api/" or we aren't using RBAC for this request, just continue - if (!request.url.path!.startsWith('/api/') || !mode.useRbacForRequest(request)) { + // if we aren't using RBAC for this request, just continue + if (!mode.useRbacForRequest(request)) { return toolkit.next(); } From 7e087633d26dfebe5cf262bbfde2cd4c29770464 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 24 Feb 2020 14:44:03 -0700 Subject: [PATCH 033/123] Remove unused indexPattern:fieldMapping:lookBack advanced setting (#58147) * Remove unused indexPattern:fieldMapping:lookBack advanced setting * Remove unused translations Co-authored-by: Elastic Machine --- docs/management/advanced-options.asciidoc | 2 -- src/legacy/core_plugins/kibana/ui_setting_defaults.js | 11 ----------- x-pack/plugins/translations/translations/ja-JP.json | 2 -- x-pack/plugins/translations/translations/zh-CN.json | 2 -- 4 files changed, 17 deletions(-) diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 80c9053dc5ae6..9d4052bbd0156 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -62,8 +62,6 @@ mentioned use "\_default_". `histogram:maxBars`:: Date histograms are not generated with more bars than the value of this property, scaling values when necessary. `history:limit`:: In fields that have history, such as query inputs, show this many recent values. -`indexPattern:fieldMapping:lookBack`:: For index patterns containing timestamps in their names, -look for this many recent matching patterns from which to query the field mapping. `indexPattern:placeholder`:: The default placeholder value to use in Management > Index Patterns > Create Index Pattern. `metaFields`:: Fields that exist outside of `_source`. Kibana merges these fields into the document when displaying it. diff --git a/src/legacy/core_plugins/kibana/ui_setting_defaults.js b/src/legacy/core_plugins/kibana/ui_setting_defaults.js index f92694eabe58d..c0628b72c2ce7 100644 --- a/src/legacy/core_plugins/kibana/ui_setting_defaults.js +++ b/src/legacy/core_plugins/kibana/ui_setting_defaults.js @@ -690,17 +690,6 @@ export function getUiSettingDefaults() { 'The maximum height that a cell in a table should occupy. Set to 0 to disable truncation', }), }, - 'indexPattern:fieldMapping:lookBack': { - name: i18n.translate('kbn.advancedSettings.indexPattern.recentMatchingTitle', { - defaultMessage: 'Recent matching patterns', - }), - value: 5, - description: i18n.translate('kbn.advancedSettings.indexPattern.recentMatchingText', { - defaultMessage: - 'For index patterns containing timestamps in their names, look for this many recent matching ' + - 'patterns from which to query the field mapping', - }), - }, 'format:defaultTypeMap': { name: i18n.translate('kbn.advancedSettings.format.defaultTypeMapTitle', { defaultMessage: 'Field type format name', diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 78bb39dd22dea..dc97a96d4fcba 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -878,8 +878,6 @@ "kbn.advancedSettings.histogram.maxBarsTitle": "最高バー数", "kbn.advancedSettings.historyLimitText": "履歴があるフィールド (例: クエリインプット) に個の数の最近の値が表示されます", "kbn.advancedSettings.historyLimitTitle": "履歴制限数", - "kbn.advancedSettings.indexPattern.recentMatchingText": "名前にタイムスタンプが含まれているインデックスパターンで、フィールドマッチングをクエリする最近の一致したパターンが、この数検索されます", - "kbn.advancedSettings.indexPattern.recentMatchingTitle": "最近一致したパターン", "kbn.advancedSettings.indexPatternPlaceholderText": "「管理 > インデックスパターン > インデックスパターンを作成」で使用される「インデックスパターン名」フィールドのプレースホルダーです。", "kbn.advancedSettings.indexPatternPlaceholderTitle": "インデックスパターンのプレースホルダー", "kbn.advancedSettings.maxBucketsText": "1 つのデータソースが返せるバケットの最大数です", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index fc9dacf0e50f7..2532cdb0c4d07 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -878,8 +878,6 @@ "kbn.advancedSettings.histogram.maxBarsTitle": "最大条形数", "kbn.advancedSettings.historyLimitText": "在具有历史记录(例如查询输入)的字段中,显示此数目的最近值", "kbn.advancedSettings.historyLimitTitle": "历史记录限制", - "kbn.advancedSettings.indexPattern.recentMatchingText": "对于名称中包含时间戳的索引模式,寻找此数目的最近匹配模式,以从其中查询字段映射", - "kbn.advancedSettings.indexPattern.recentMatchingTitle": "最近匹配模式", "kbn.advancedSettings.indexPatternPlaceholderText": "在“管理 > 索引模式 > 创建索引模式”中“索引模式名称”的占位符。", "kbn.advancedSettings.indexPatternPlaceholderTitle": "索引模式占位符", "kbn.advancedSettings.maxBucketsText": "单个数据源可以返回的最大存储桶数目", From 13eacb51f0fd030f123c05e68c545bdb99f6ac70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Mon, 24 Feb 2020 23:43:40 +0100 Subject: [PATCH 034/123] [APM] Stabilize agent configuration API (#57767) --- docs/apm/api.asciidoc | 260 ++++++++++++++++++ docs/apm/index.asciidoc | 2 + .../AddEditFlyout/DeleteButton.tsx | 10 +- .../AddEditFlyout/index.tsx | 2 +- .../AddEditFlyout/saveConfig.ts | 30 +- x-pack/legacy/plugins/apm/readme.md | 22 ++ .../index.test.ts | 41 +++ .../agent_configuration_intake_rt/index.ts | 26 ++ .../apm/server/lib/helpers/es_client.ts | 7 +- .../lib/services/get_service_node_metadata.ts | 4 +- .../__snapshots__/queries.test.ts.snap | 234 ++++++++++------ .../configuration_types.d.ts | 19 +- .../create_or_update_configuration.ts | 22 +- .../find_exact_configuration.ts | 46 ++++ .../get_agent_name_by_service.ts | 6 +- .../agent_configuration/queries.test.ts | 146 ++++++---- .../{search.ts => search_configurations.ts} | 35 ++- .../apm/server/routes/create_apm_api.ts | 6 +- .../routes/settings/agent_configuration.ts | 137 ++++----- .../apis/apm/agent_configuration.ts | 163 ++++++----- .../apis/apm/feature_controls.ts | 42 +-- x-pack/test/api_integration/apis/apm/index.ts | 2 +- x-pack/test/functional/apps/apm/index.ts | 2 +- 23 files changed, 894 insertions(+), 370 deletions(-) create mode 100644 docs/apm/api.asciidoc create mode 100644 x-pack/plugins/apm/common/runtime_types/agent_configuration_intake_rt/index.test.ts create mode 100644 x-pack/plugins/apm/common/runtime_types/agent_configuration_intake_rt/index.ts create mode 100644 x-pack/plugins/apm/server/lib/settings/agent_configuration/find_exact_configuration.ts rename x-pack/plugins/apm/server/lib/settings/agent_configuration/{search.ts => search_configurations.ts} (68%) diff --git a/docs/apm/api.asciidoc b/docs/apm/api.asciidoc new file mode 100644 index 0000000000000..b520cc46bef8d --- /dev/null +++ b/docs/apm/api.asciidoc @@ -0,0 +1,260 @@ +[role="xpack"] +[[apm-api]] +== API + +Some APM app features are provided via a REST API: + +* <> + +TIP: Kibana provides additional <>, +and general information on <>. + +//// +******************************************************* +//// + +[[agent-config-api]] +=== Agent Configuration API + +The Agent configuration API allows you to fine-tune your APM agent configuration, +without needing to redeploy your application. + +The following Agent configuration APIs are available: + +* <> to create or update an Agent configuration +* <> to delete an Agent configuration. +* <> to list all Agent configurations. +* <> to search for an Agent configuration. + +//// +******************************************************* +//// + +[[apm-update-config]] +==== Create or update configuration + +[[apm-update-config-req]] +===== Request + +`PUT /api/apm/settings/agent-configuration` + +[[apm-update-config-req-body]] +===== Request body + +`service`:: +(required, object) Service identifying the configuration to create or update. + +`name` ::: + (required, string) Name of service + +`environment` ::: + (optional, string) Environment of service + +`settings`:: +(required) Key/value object with settings and their corresponding value. + +`agent_name`:: +(optional) The agent name is used by the UI to determine which settings to display. + + +[[apm-update-config-example]] +===== Example + +[source,console] +-------------------------------------------------- +PUT /api/apm/settings/agent-configuration +{ + "service" : { + "name" : "frontend", + "environment" : "production" + }, + "settings" : { + "transaction_sample_rate" : 0.4, + "capture_body" : "off", + "transaction_max_spans" : 500 + }, + "agent_name": "nodejs" +} +-------------------------------------------------- + +//// +******************************************************* +//// + + +[[apm-delete-config]] +==== Delete configuration + +[[apm-delete-config-req]] +===== Request + +`DELETE /api/apm/settings/agent-configuration` + +[[apm-delete-config-req-body]] +===== Request body +`service`:: +(required, object) Service identifying the configuration to delete + +`name` ::: + (required, string) Name of service + +`environment` ::: + (optional, string) Environment of service + + +[[apm-delete-config-example]] +===== Example + +[source,console] +-------------------------------------------------- +DELETE /api/apm/settings/agent-configuration +{ + "service" : { + "name" : "frontend", + "environment": "production" + } +} +-------------------------------------------------- + +//// +******************************************************* +//// + + +[[apm-list-config]] +==== List configuration + + +[[apm-list-config-req]] +===== Request + +`GET /api/apm/settings/agent-configuration` + +[[apm-list-config-body]] +===== Response body + +[source,js] +-------------------------------------------------- +[ + { + "agent_name": "go", + "service": { + "name": "opbeans-go", + "environment": "production" + }, + "settings": { + "transaction_sample_rate": 1, + "capture_body": "off", + "transaction_max_spans": 200 + }, + "@timestamp": 1581934104843, + "applied_by_agent": false, + "etag": "1e58c178efeebae15c25c539da740d21dee422fc" + }, + { + "agent_name": "go", + "service": { + "name": "opbeans-go" + }, + "settings": { + "transaction_sample_rate": 1, + "capture_body": "off", + "transaction_max_spans": 300 + }, + "@timestamp": 1581934111727, + "applied_by_agent": false, + "etag": "3eed916d3db434d9fb7f039daa681c7a04539a64" + }, + { + "agent_name": "nodejs", + "service": { + "name": "frontend" + }, + "settings": { + "transaction_sample_rate": 1, + }, + "@timestamp": 1582031336265, + "applied_by_agent": false, + "etag": "5080ed25785b7b19f32713681e79f46996801a5b" + } +] +-------------------------------------------------- + +[[apm-list-config-example]] +===== Example + +[source,console] +-------------------------------------------------- +GET /api/apm/settings/agent-configuration +-------------------------------------------------- + +//// +******************************************************* +//// + + +[[apm-search-config]] +==== Search configuration + +[[apm-search-config-req]] +===== Request + +`POST /api/apm/settings/agent-configuration/search` + +[[apm-search-config-req-body]] +===== Request body + +`service`:: +(required, object) Service identifying the configuration. + +`name` ::: + (required, string) Name of service + +`environment` ::: + (optional, string) Environment of service + +`etag`:: +(required) etag is sent by the agent to indicate the etag of the last successfully applied configuration. If the etag matches an existing configuration its `applied_by_agent` property will be set to `true`. Every time a configuration is edited `applied_by_agent` is reset to `false`. + +[[apm-search-config-body]] +===== Response body + +[source,js] +-------------------------------------------------- +{ + "_index": ".apm-agent-configuration", + "_id": "CIaqXXABmQCdPphWj8EJ", + "_score": 2, + "_source": { + "agent_name": "nodejs", + "service": { + "name": "frontend" + }, + "settings": { + "transaction_sample_rate": 1, + }, + "@timestamp": 1582031336265, + "applied_by_agent": false, + "etag": "5080ed25785b7b19f32713681e79f46996801a5b" + } +} +-------------------------------------------------- + +[[apm-search-config-example]] +===== Example + +[source,console] +-------------------------------------------------- +POST /api/apm/settings/agent-configuration/search +{ + "etag" : "1e58c178efeebae15c25c539da740d21dee422fc", + "service" : { + "name" : "frontend", + "environment": "production" + } +} +-------------------------------------------------- + +//// +******************************************************* +//// diff --git a/docs/apm/index.asciidoc b/docs/apm/index.asciidoc index 7eb7278cf0358..d3f0dc5b7f11f 100644 --- a/docs/apm/index.asciidoc +++ b/docs/apm/index.asciidoc @@ -24,3 +24,5 @@ include::getting-started.asciidoc[] include::bottlenecks.asciidoc[] include::using-the-apm-ui.asciidoc[] + +include::api.asciidoc[] diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/DeleteButton.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/DeleteButton.tsx index 496147b02589b..1564f1ae746a9 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/DeleteButton.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/DeleteButton.tsx @@ -51,12 +51,18 @@ async function deleteConfig( ) { try { await callApmApi({ - pathname: '/api/apm/settings/agent-configuration/{configurationId}', + pathname: '/api/apm/settings/agent-configuration', method: 'DELETE', params: { - path: { configurationId: selectedConfig.id } + body: { + service: { + name: selectedConfig.service.name, + environment: selectedConfig.service.environment + } + } } }); + toasts.addSuccess({ title: i18n.translate( 'xpack.apm.settings.agentConf.flyout.deleteSection.deleteConfigSucceededTitle', diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/index.tsx index 653dedea733f2..c77617fbb424f 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/index.tsx @@ -135,8 +135,8 @@ export function AddEditFlyout({ sampleRate, captureBody, transactionMaxSpans, - configurationId: selectedConfig ? selectedConfig.id : undefined, agentName, + isExistingConfig: Boolean(selectedConfig), toasts, trackApmEvent }); diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/saveConfig.ts b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/saveConfig.ts index 19934cafb4694..d36120a054795 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/saveConfig.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/saveConfig.ts @@ -27,8 +27,8 @@ export async function saveConfig({ sampleRate, captureBody, transactionMaxSpans, - configurationId, agentName, + isExistingConfig, toasts, trackApmEvent }: { @@ -38,8 +38,8 @@ export async function saveConfig({ sampleRate: string; captureBody: string; transactionMaxSpans: string; - configurationId?: string; agentName?: string; + isExistingConfig: boolean; toasts: NotificationsStart['toasts']; trackApmEvent: UiTracker; }) { @@ -64,24 +64,14 @@ export async function saveConfig({ settings }; - if (configurationId) { - await callApmApi({ - pathname: '/api/apm/settings/agent-configuration/{configurationId}', - method: 'PUT', - params: { - path: { configurationId }, - body: configuration - } - }); - } else { - await callApmApi({ - pathname: '/api/apm/settings/agent-configuration/new', - method: 'POST', - params: { - body: configuration - } - }); - } + await callApmApi({ + pathname: '/api/apm/settings/agent-configuration', + method: 'PUT', + params: { + query: { overwrite: isExistingConfig }, + body: configuration + } + }); toasts.addSuccess({ title: i18n.translate( diff --git a/x-pack/legacy/plugins/apm/readme.md b/x-pack/legacy/plugins/apm/readme.md index 2106243d12aea..a513249c296db 100644 --- a/x-pack/legacy/plugins/apm/readme.md +++ b/x-pack/legacy/plugins/apm/readme.md @@ -71,6 +71,28 @@ node scripts/jest.js plugins/apm --watch node scripts/jest.js plugins/apm --updateSnapshot ``` +### Functional tests + +**Start server** +`node scripts/functional_tests_server --config x-pack/test/functional/config.js` + +**Run tests** +`node scripts/functional_test_runner --config x-pack/test/functional/config.js --grep='APM specs'` + +APM tests are located in `x-pack/test/functional/apps/apm`. +For debugging access Elasticsearch on http://localhost:9220` (elastic/changeme) + +### API integration tests + +**Start server** +`node scripts/functional_tests_server --config x-pack/test/api_integration/config.js` + +**Run tests** +`node scripts/functional_test_runner --config x-pack/test/api_integration/config.js --grep='APM specs'` + +APM tests are located in `x-pack/test/api_integration/apis/apm`. +For debugging access Elasticsearch on http://localhost:9220` (elastic/changeme) + ### Linting _Note: Run the following commands from `kibana/`._ diff --git a/x-pack/plugins/apm/common/runtime_types/agent_configuration_intake_rt/index.test.ts b/x-pack/plugins/apm/common/runtime_types/agent_configuration_intake_rt/index.test.ts new file mode 100644 index 0000000000000..4c9dc78eb41e9 --- /dev/null +++ b/x-pack/plugins/apm/common/runtime_types/agent_configuration_intake_rt/index.test.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { agentConfigurationIntakeRt } from './index'; +import { isRight } from 'fp-ts/lib/Either'; + +describe('agentConfigurationIntakeRt', () => { + it('is valid when required parameters are given', () => { + const config = { + service: {}, + settings: {} + }; + + expect(isConfigValid(config)).toBe(true); + }); + + it('is valid when required and optional parameters are given', () => { + const config = { + service: { name: 'my-service', environment: 'my-environment' }, + settings: { + transaction_sample_rate: 0.5, + capture_body: 'foo', + transaction_max_spans: 10 + } + }; + + expect(isConfigValid(config)).toBe(true); + }); + + it('is invalid when required parameters are not given', () => { + const config = {}; + expect(isConfigValid(config)).toBe(false); + }); +}); + +function isConfigValid(config: any) { + return isRight(agentConfigurationIntakeRt.decode(config)); +} diff --git a/x-pack/plugins/apm/common/runtime_types/agent_configuration_intake_rt/index.ts b/x-pack/plugins/apm/common/runtime_types/agent_configuration_intake_rt/index.ts new file mode 100644 index 0000000000000..32a2832b5eaf3 --- /dev/null +++ b/x-pack/plugins/apm/common/runtime_types/agent_configuration_intake_rt/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as t from 'io-ts'; +import { transactionSampleRateRt } from '../transaction_sample_rate_rt'; +import { transactionMaxSpansRt } from '../transaction_max_spans_rt'; + +export const serviceRt = t.partial({ + name: t.string, + environment: t.string +}); + +export const agentConfigurationIntakeRt = t.intersection([ + t.partial({ agent_name: t.string }), + t.type({ + service: serviceRt, + settings: t.partial({ + transaction_sample_rate: transactionSampleRateRt, + capture_body: t.string, + transaction_max_spans: transactionMaxSpansRt + }) + }) +]); diff --git a/x-pack/plugins/apm/server/lib/helpers/es_client.ts b/x-pack/plugins/apm/server/lib/helpers/es_client.ts index 8ada02d085631..86eb1dba507f0 100644 --- a/x-pack/plugins/apm/server/lib/helpers/es_client.ts +++ b/x-pack/plugins/apm/server/lib/helpers/es_client.ts @@ -7,9 +7,10 @@ /* eslint-disable no-console */ import { IndexDocumentParams, - IndicesCreateParams, IndicesDeleteParams, - SearchParams + SearchParams, + IndicesCreateParams, + DeleteDocumentResponse } from 'elasticsearch'; import { cloneDeep, isString, merge, uniqueId } from 'lodash'; import { KibanaRequest } from 'src/core/server'; @@ -188,7 +189,7 @@ export function getESClient( index: (params: APMIndexDocumentParams) => { return withTime(() => callMethod('index', params)); }, - delete: (params: IndicesDeleteParams) => { + delete: (params: IndicesDeleteParams): Promise => { return withTime(() => callMethod('delete', params)); }, indicesCreate: (params: IndicesCreateParams) => { diff --git a/x-pack/plugins/apm/server/lib/services/get_service_node_metadata.ts b/x-pack/plugins/apm/server/lib/services/get_service_node_metadata.ts index 7120d3bca6c25..ccd8b123e23e2 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_node_metadata.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_node_metadata.ts @@ -58,8 +58,8 @@ export async function getServiceNodeMetadata({ const response = await client.search(query); return { - host: response.aggregations?.host.buckets[0].key || NOT_AVAILABLE_LABEL, + host: response.aggregations?.host.buckets[0]?.key || NOT_AVAILABLE_LABEL, containerId: - response.aggregations?.containerId.buckets[0].key || NOT_AVAILABLE_LABEL + response.aggregations?.containerId.buckets[0]?.key || NOT_AVAILABLE_LABEL }; } diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/settings/agent_configuration/__snapshots__/queries.test.ts.snap index 542fdd99e2635..db34b4d5d20b5 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/__snapshots__/queries.test.ts.snap @@ -1,6 +1,90 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`agent configuration queries fetches all environments 1`] = ` +exports[`agent configuration queries findExactConfiguration find configuration by service.environment 1`] = ` +Object { + "body": Object { + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "must_not": Array [ + Object { + "exists": Object { + "field": "service.name", + }, + }, + ], + }, + }, + Object { + "term": Object { + "service.environment": "bar", + }, + }, + ], + }, + }, + }, + "index": "myIndex", +} +`; + +exports[`agent configuration queries findExactConfiguration find configuration by service.name 1`] = ` +Object { + "body": Object { + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "term": Object { + "service.name": "foo", + }, + }, + Object { + "bool": Object { + "must_not": Array [ + Object { + "exists": Object { + "field": "service.environment", + }, + }, + ], + }, + }, + ], + }, + }, + }, + "index": "myIndex", +} +`; + +exports[`agent configuration queries findExactConfiguration find configuration by service.name and service.environment 1`] = ` +Object { + "body": Object { + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "term": Object { + "service.name": "foo", + }, + }, + Object { + "term": Object { + "service.environment": "bar", + }, + }, + ], + }, + }, + }, + "index": "myIndex", +} +`; + +exports[`agent configuration queries getAllEnvironments fetches all environments 1`] = ` Object { "body": Object { "aggs": Object { @@ -41,14 +125,79 @@ Object { } `; -exports[`agent configuration queries fetches configurations 1`] = ` +exports[`agent configuration queries getExistingEnvironmentsForService fetches unavailable environments 1`] = ` +Object { + "body": Object { + "aggs": Object { + "environments": Object { + "terms": Object { + "field": "service.environment", + "missing": "ALL_OPTION_VALUE", + "size": 50, + }, + }, + }, + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "term": Object { + "service.name": "foo", + }, + }, + ], + }, + }, + "size": 0, + }, + "index": "myIndex", +} +`; + +exports[`agent configuration queries getServiceNames fetches service names 1`] = ` +Object { + "body": Object { + "aggs": Object { + "services": Object { + "terms": Object { + "field": "service.name", + "size": 50, + }, + }, + }, + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "terms": Object { + "processor.event": Array [ + "transaction", + "error", + "metric", + ], + }, + }, + ], + }, + }, + "size": 0, + }, + "index": Array [ + "myIndex", + "myIndex", + "myIndex", + ], +} +`; + +exports[`agent configuration queries listConfigurations fetches configurations 1`] = ` Object { "index": "myIndex", "size": 200, } `; -exports[`agent configuration queries fetches filtered configurations with an environment 1`] = ` +exports[`agent configuration queries searchConfigurations fetches filtered configurations with an environment 1`] = ` Object { "body": Object { "query": Object { @@ -60,9 +209,7 @@ Object { "boost": 2, "filter": Object { "term": Object { - "service.name": Object { - "value": "foo", - }, + "service.name": "foo", }, }, }, @@ -72,9 +219,7 @@ Object { "boost": 1, "filter": Object { "term": Object { - "service.environment": Object { - "value": "bar", - }, + "service.environment": "bar", }, }, }, @@ -109,7 +254,7 @@ Object { } `; -exports[`agent configuration queries fetches filtered configurations without an environment 1`] = ` +exports[`agent configuration queries searchConfigurations fetches filtered configurations without an environment 1`] = ` Object { "body": Object { "query": Object { @@ -121,9 +266,7 @@ Object { "boost": 2, "filter": Object { "term": Object { - "service.name": Object { - "value": "foo", - }, + "service.name": "foo", }, }, }, @@ -157,68 +300,3 @@ Object { "index": "myIndex", } `; - -exports[`agent configuration queries fetches service names 1`] = ` -Object { - "body": Object { - "aggs": Object { - "services": Object { - "terms": Object { - "field": "service.name", - "size": 50, - }, - }, - }, - "query": Object { - "bool": Object { - "filter": Array [ - Object { - "terms": Object { - "processor.event": Array [ - "transaction", - "error", - "metric", - ], - }, - }, - ], - }, - }, - "size": 0, - }, - "index": Array [ - "myIndex", - "myIndex", - "myIndex", - ], -} -`; - -exports[`agent configuration queries fetches unavailable environments 1`] = ` -Object { - "body": Object { - "aggs": Object { - "environments": Object { - "terms": Object { - "field": "service.environment", - "missing": "ALL_OPTION_VALUE", - "size": 50, - }, - }, - }, - "query": Object { - "bool": Object { - "filter": Array [ - Object { - "term": Object { - "service.name": "foo", - }, - }, - ], - }, - }, - "size": 0, - }, - "index": "myIndex", -} -`; diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/configuration_types.d.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/configuration_types.d.ts index ea8f50c90c1d3..ddbe6892c5441 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/configuration_types.d.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/configuration_types.d.ts @@ -4,18 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -export interface AgentConfiguration { +import t from 'io-ts'; +import { agentConfigurationIntakeRt } from '../../../../common/runtime_types/agent_configuration_intake_rt'; + +export type AgentConfigurationIntake = t.TypeOf< + typeof agentConfigurationIntakeRt +>; +export type AgentConfiguration = { '@timestamp': number; applied_by_agent?: boolean; etag?: string; agent_name?: string; - service: { - name?: string; - environment?: string; - }; - settings: { - transaction_sample_rate?: number; - capture_body?: string; - transaction_max_spans?: number; - }; -} +} & AgentConfigurationIntake; diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/create_or_update_configuration.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/create_or_update_configuration.ts index 5a67f78de6f65..74fcc61dde863 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/create_or_update_configuration.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/create_or_update_configuration.ts @@ -6,19 +6,19 @@ import hash from 'object-hash'; import { Setup } from '../../helpers/setup_request'; -import { AgentConfiguration } from './configuration_types'; +import { + AgentConfiguration, + AgentConfigurationIntake +} from './configuration_types'; import { APMIndexDocumentParams } from '../../helpers/es_client'; export async function createOrUpdateConfiguration({ configurationId, - configuration, + configurationIntake, setup }: { configurationId?: string; - configuration: Omit< - AgentConfiguration, - '@timestamp' | 'applied_by_agent' | 'etag' - >; + configurationIntake: AgentConfigurationIntake; setup: Setup; }) { const { internalClient, indices } = setup; @@ -27,15 +27,15 @@ export async function createOrUpdateConfiguration({ refresh: true, index: indices.apmAgentConfigurationIndex, body: { - agent_name: configuration.agent_name, + agent_name: configurationIntake.agent_name, service: { - name: configuration.service.name, - environment: configuration.service.environment + name: configurationIntake.service.name, + environment: configurationIntake.service.environment }, - settings: configuration.settings, + settings: configurationIntake.settings, '@timestamp': Date.now(), applied_by_agent: false, - etag: hash(configuration) + etag: hash(configurationIntake) } }; diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/find_exact_configuration.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/find_exact_configuration.ts new file mode 100644 index 0000000000000..eea409882f876 --- /dev/null +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/find_exact_configuration.ts @@ -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 { + SERVICE_NAME, + SERVICE_ENVIRONMENT +} from '../../../../common/elasticsearch_fieldnames'; +import { Setup } from '../../helpers/setup_request'; +import { AgentConfiguration } from './configuration_types'; +import { ESSearchHit } from '../../../../typings/elasticsearch'; + +export async function findExactConfiguration({ + service, + setup +}: { + service: AgentConfiguration['service']; + setup: Setup; +}) { + const { internalClient, indices } = setup; + + const serviceNameFilter = service.name + ? { term: { [SERVICE_NAME]: service.name } } + : { bool: { must_not: [{ exists: { field: SERVICE_NAME } }] } }; + + const environmentFilter = service.environment + ? { term: { [SERVICE_ENVIRONMENT]: service.environment } } + : { bool: { must_not: [{ exists: { field: SERVICE_ENVIRONMENT } }] } }; + + const params = { + index: indices.apmAgentConfigurationIndex, + body: { + query: { + bool: { filter: [serviceNameFilter, environmentFilter] } + } + } + }; + + const resp = await internalClient.search( + params + ); + + return resp.hits.hits[0] as ESSearchHit | undefined; +} diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_agent_name_by_service.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_agent_name_by_service.ts index dccf8b110d082..a9af1f6174fd5 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_agent_name_by_service.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_agent_name_by_service.ts @@ -48,8 +48,6 @@ export async function getAgentNameByService({ }; const { aggregations } = await client.search(params); - const agentName = aggregations?.agent_names.buckets[0].key as - | string - | undefined; - return { agentName }; + const agentName = aggregations?.agent_names.buckets[0]?.key; + return agentName as string | undefined; } diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/queries.test.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/queries.test.ts index a82d148781ad8..b951b7f350eed 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/queries.test.ts @@ -8,11 +8,12 @@ import { getAllEnvironments } from './get_environments/get_all_environments'; import { getExistingEnvironmentsForService } from './get_environments/get_existing_environments_for_service'; import { getServiceNames } from './get_service_names'; import { listConfigurations } from './list_configurations'; -import { searchConfigurations } from './search'; +import { searchConfigurations } from './search_configurations'; import { SearchParamsMock, inspectSearchParams } from '../../../../../../legacy/plugins/apm/public/utils/testHelpers'; +import { findExactConfiguration } from './find_exact_configuration'; describe('agent configuration queries', () => { let mock: SearchParamsMock; @@ -21,68 +22,117 @@ describe('agent configuration queries', () => { mock.teardown(); }); - it('fetches all environments', async () => { - mock = await inspectSearchParams(setup => - getAllEnvironments({ - serviceName: 'foo', - setup - }) - ); + describe('getAllEnvironments', () => { + it('fetches all environments', async () => { + mock = await inspectSearchParams(setup => + getAllEnvironments({ + serviceName: 'foo', + setup + }) + ); - expect(mock.params).toMatchSnapshot(); + expect(mock.params).toMatchSnapshot(); + }); }); - it('fetches unavailable environments', async () => { - mock = await inspectSearchParams(setup => - getExistingEnvironmentsForService({ - serviceName: 'foo', - setup - }) - ); + describe('getExistingEnvironmentsForService', () => { + it('fetches unavailable environments', async () => { + mock = await inspectSearchParams(setup => + getExistingEnvironmentsForService({ + serviceName: 'foo', + setup + }) + ); - expect(mock.params).toMatchSnapshot(); + expect(mock.params).toMatchSnapshot(); + }); }); - it('fetches service names', async () => { - mock = await inspectSearchParams(setup => - getServiceNames({ - setup - }) - ); + describe('getServiceNames', () => { + it('fetches service names', async () => { + mock = await inspectSearchParams(setup => + getServiceNames({ + setup + }) + ); - expect(mock.params).toMatchSnapshot(); + expect(mock.params).toMatchSnapshot(); + }); }); - it('fetches configurations', async () => { - mock = await inspectSearchParams(setup => - listConfigurations({ - setup - }) - ); + describe('listConfigurations', () => { + it('fetches configurations', async () => { + mock = await inspectSearchParams(setup => + listConfigurations({ + setup + }) + ); - expect(mock.params).toMatchSnapshot(); + expect(mock.params).toMatchSnapshot(); + }); }); - it('fetches filtered configurations without an environment', async () => { - mock = await inspectSearchParams(setup => - searchConfigurations({ - serviceName: 'foo', - setup - }) - ); + describe('searchConfigurations', () => { + it('fetches filtered configurations without an environment', async () => { + mock = await inspectSearchParams(setup => + searchConfigurations({ + service: { + name: 'foo' + }, + setup + }) + ); - expect(mock.params).toMatchSnapshot(); + expect(mock.params).toMatchSnapshot(); + }); + + it('fetches filtered configurations with an environment', async () => { + mock = await inspectSearchParams(setup => + searchConfigurations({ + service: { + name: 'foo', + environment: 'bar' + }, + setup + }) + ); + + expect(mock.params).toMatchSnapshot(); + }); }); - it('fetches filtered configurations with an environment', async () => { - mock = await inspectSearchParams(setup => - searchConfigurations({ - serviceName: 'foo', - environment: 'bar', - setup - }) - ); + describe('findExactConfiguration', () => { + it('find configuration by service.name', async () => { + mock = await inspectSearchParams(setup => + findExactConfiguration({ + service: { name: 'foo' }, + setup + }) + ); + + expect(mock.params).toMatchSnapshot(); + }); + + it('find configuration by service.environment', async () => { + mock = await inspectSearchParams(setup => + findExactConfiguration({ + service: { environment: 'bar' }, + setup + }) + ); + + expect(mock.params).toMatchSnapshot(); + }); + + it('find configuration by service.name and service.environment', async () => { + mock = await inspectSearchParams(setup => + findExactConfiguration({ + service: { name: 'foo', environment: 'bar' }, + setup + }) + ); - expect(mock.params).toMatchSnapshot(); + expect(mock.params).toMatchSnapshot(); + }); }); }); diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/search.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/search_configurations.ts similarity index 68% rename from x-pack/plugins/apm/server/lib/settings/agent_configuration/search.ts rename to x-pack/plugins/apm/server/lib/settings/agent_configuration/search_configurations.ts index 766baead006b6..9bbdc96a3a797 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/search.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/search_configurations.ts @@ -12,29 +12,39 @@ import { Setup } from '../../helpers/setup_request'; import { AgentConfiguration } from './configuration_types'; export async function searchConfigurations({ - serviceName, - environment, + service, setup }: { - serviceName: string; - environment?: string; + service: AgentConfiguration['service']; setup: Setup; }) { const { internalClient, indices } = setup; - const environmentFilter = environment + + // In the following `constant_score` is being used to disable IDF calculation (where frequency of a term influences scoring). + // Additionally a boost has been added to service.name to ensure it scores higher. + // If there is tie between a config with a matching service.name and a config with a matching environment, the config that matches service.name wins + const serviceNameFilter = service.name + ? [ + { + constant_score: { + filter: { term: { [SERVICE_NAME]: service.name } }, + boost: 2 + } + } + ] + : []; + + const environmentFilter = service.environment ? [ { constant_score: { - filter: { term: { [SERVICE_ENVIRONMENT]: { value: environment } } }, + filter: { term: { [SERVICE_ENVIRONMENT]: service.environment } }, boost: 1 } } ] : []; - // In the following `constant_score` is being used to disable IDF calculation (where frequency of a term influences scoring) - // Additionally a boost has been added to service.name to ensure it scores higher - // if there is tie between a config with a matching service.name and a config with a matching environment const params = { index: indices.apmAgentConfigurationIndex, body: { @@ -42,12 +52,7 @@ export async function searchConfigurations({ bool: { minimum_should_match: 2, should: [ - { - constant_score: { - filter: { term: { [SERVICE_NAME]: { value: serviceName } } }, - boost: 2 - } - }, + ...serviceNameFilter, ...environmentFilter, { bool: { must_not: [{ exists: { field: SERVICE_NAME } }] } }, { bool: { must_not: [{ exists: { field: SERVICE_ENVIRONMENT } }] } } 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 f65e271389938..21392edbb2c48 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -23,11 +23,10 @@ import { import { agentConfigurationRoute, agentConfigurationSearchRoute, - createAgentConfigurationRoute, deleteAgentConfigurationRoute, listAgentConfigurationEnvironmentsRoute, listAgentConfigurationServicesRoute, - updateAgentConfigurationRoute, + createOrUpdateAgentConfigurationRoute, agentConfigurationAgentNameRoute } from './settings/agent_configuration'; import { @@ -83,11 +82,10 @@ const createApmApi = () => { .add(agentConfigurationAgentNameRoute) .add(agentConfigurationRoute) .add(agentConfigurationSearchRoute) - .add(createAgentConfigurationRoute) .add(deleteAgentConfigurationRoute) .add(listAgentConfigurationEnvironmentsRoute) .add(listAgentConfigurationServicesRoute) - .add(updateAgentConfigurationRoute) + .add(createOrUpdateAgentConfigurationRoute) // APM indices .add(apmIndexSettingsRoute) diff --git a/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts b/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts index ddd6a27025131..83b845b1fc436 100644 --- a/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts +++ b/x-pack/plugins/apm/server/routes/settings/agent_configuration.ts @@ -9,15 +9,19 @@ import Boom from 'boom'; import { setupRequest } from '../../lib/helpers/setup_request'; import { getServiceNames } from '../../lib/settings/agent_configuration/get_service_names'; import { createOrUpdateConfiguration } from '../../lib/settings/agent_configuration/create_or_update_configuration'; -import { searchConfigurations } from '../../lib/settings/agent_configuration/search'; +import { searchConfigurations } from '../../lib/settings/agent_configuration/search_configurations'; +import { findExactConfiguration } from '../../lib/settings/agent_configuration/find_exact_configuration'; import { listConfigurations } from '../../lib/settings/agent_configuration/list_configurations'; import { getEnvironments } from '../../lib/settings/agent_configuration/get_environments'; import { deleteConfiguration } from '../../lib/settings/agent_configuration/delete_configuration'; import { createRoute } from '../create_route'; -import { transactionSampleRateRt } from '../../../common/runtime_types/transaction_sample_rate_rt'; -import { transactionMaxSpansRt } from '../../../common/runtime_types/transaction_max_spans_rt'; import { getAgentNameByService } from '../../lib/settings/agent_configuration/get_agent_name_by_service'; import { markAppliedByAgent } from '../../lib/settings/agent_configuration/mark_applied_by_agent'; +import { + serviceRt, + agentConfigurationIntakeRt +} from '../../../common/runtime_types/agent_configuration_intake_rt'; +import { jsonRt } from '../../../common/runtime_types/json_rt'; // get list of configurations export const agentConfigurationRoute = createRoute(core => ({ @@ -31,20 +35,34 @@ export const agentConfigurationRoute = createRoute(core => ({ // delete configuration export const deleteAgentConfigurationRoute = createRoute(() => ({ method: 'DELETE', - path: '/api/apm/settings/agent-configuration/{configurationId}', + path: '/api/apm/settings/agent-configuration', options: { tags: ['access:apm', 'access:apm_write'] }, params: { - path: t.type({ - configurationId: t.string + body: t.type({ + service: serviceRt }) }, handler: async ({ context, request }) => { const setup = await setupRequest(context, request); - const { configurationId } = context.params.path; + const { service } = context.params.body; + + const config = await findExactConfiguration({ service, setup }); + if (!config) { + context.logger.info( + `Config was not found for ${service.name}/${service.environment}` + ); + + throw Boom.notFound(); + } + + context.logger.info( + `Deleting config ${service.name}/${service.environment} (${config._id})` + ); + return await deleteConfiguration({ - configurationId, + configurationId: config._id, setup }); } @@ -62,23 +80,6 @@ export const listAgentConfigurationServicesRoute = createRoute(() => ({ } })); -const agentPayloadRt = t.intersection([ - t.partial({ agent_name: t.string }), - t.type({ - service: t.intersection([ - t.partial({ name: t.string }), - t.partial({ environment: t.string }) - ]) - }), - t.type({ - settings: t.intersection([ - t.partial({ transaction_sample_rate: transactionSampleRateRt }), - t.partial({ capture_body: t.string }), - t.partial({ transaction_max_spans: transactionMaxSpansRt }) - ]) - }) -]); - // get environments for service export const listAgentConfigurationEnvironmentsRoute = createRoute(() => ({ path: '/api/apm/settings/agent-configuration/environments', @@ -102,55 +103,47 @@ export const agentConfigurationAgentNameRoute = createRoute(() => ({ const setup = await setupRequest(context, request); const { serviceName } = context.params.query; const agentName = await getAgentNameByService({ serviceName, setup }); - return agentName; + return { agentName }; } })); -export const createAgentConfigurationRoute = createRoute(() => ({ - method: 'POST', - path: '/api/apm/settings/agent-configuration/new', - params: { - body: agentPayloadRt - }, +export const createOrUpdateAgentConfigurationRoute = createRoute(() => ({ + method: 'PUT', + path: '/api/apm/settings/agent-configuration', options: { tags: ['access:apm', 'access:apm_write'] }, + params: { + query: t.partial({ overwrite: jsonRt.pipe(t.boolean) }), + body: agentConfigurationIntakeRt + }, handler: async ({ context, request }) => { const setup = await setupRequest(context, request); - const configuration = context.params.body; + const { body, query } = context.params; - // TODO: Remove logger. Only added temporarily to debug flaky test (https://github.com/elastic/kibana/issues/51764) - context.logger.info( - `Hitting: /api/apm/settings/agent-configuration/new with ${configuration.service.name}/${configuration.service.environment}` - ); - const res = await createOrUpdateConfiguration({ - configuration, + // if the config already exists, it is fetched and updated + // this is to avoid creating two configs with identical service params + const config = await findExactConfiguration({ + service: body.service, setup }); - context.logger.info(`Created agent configuration`); - return res; - } -})); + // if the config exists ?overwrite=true is required + if (config && !query.overwrite) { + throw Boom.badRequest( + `A configuration already exists for "${body.service.name}/${body.service.environment}. Use ?overwrite=true to overwrite the existing configuration.` + ); + } + + context.logger.info( + `${config ? 'Updating' : 'Creating'} config ${body.service.name}/${ + body.service.environment + }` + ); -export const updateAgentConfigurationRoute = createRoute(() => ({ - method: 'PUT', - path: '/api/apm/settings/agent-configuration/{configurationId}', - options: { - tags: ['access:apm', 'access:apm_write'] - }, - params: { - path: t.type({ - configurationId: t.string - }), - body: agentPayloadRt - }, - handler: async ({ context, request }) => { - const setup = await setupRequest(context, request); - const { configurationId } = context.params.path; return await createOrUpdateConfiguration({ - configurationId, - configuration: context.params.body, + configurationId: config?._id, + configurationIntake: body, setup }); } @@ -162,41 +155,33 @@ export const agentConfigurationSearchRoute = createRoute(core => ({ path: '/api/apm/settings/agent-configuration/search', params: { body: t.type({ - service: t.intersection([ - t.type({ name: t.string }), - t.partial({ environment: t.string }) - ]), + service: serviceRt, etag: t.string }) }, handler: async ({ context, request }) => { - const { body } = context.params; - - // TODO: Remove logger. Only added temporarily to debug flaky test (https://github.com/elastic/kibana/issues/51764) - context.logger.info( - `Hitting: /api/apm/settings/agent-configuration/search for ${body.service.name}/${body.service.environment}` - ); + const { service, etag } = context.params.body; const setup = await setupRequest(context, request); const config = await searchConfigurations({ - serviceName: body.service.name, - environment: body.service.environment, + service, setup }); if (!config) { context.logger.info( - `Config was not found for ${body.service.name}/${body.service.environment}` + `Config was not found for ${service.name}/${service.environment}` ); - throw new Boom('Not found', { statusCode: 404 }); + throw Boom.notFound(); } context.logger.info( - `Config was found for ${body.service.name}/${body.service.environment}` + `Config was found for ${service.name}/${service.environment}` ); // update `applied_by_agent` field if etags match - if (body.etag === config._source.etag && !config._source.applied_by_agent) { + // this happens in the background and doesn't block the response + if (etag === config._source.etag && !config._source.applied_by_agent) { markAppliedByAgent({ id: config._id, body: config._source, setup }); } diff --git a/x-pack/test/api_integration/apis/apm/agent_configuration.ts b/x-pack/test/api_integration/apis/apm/agent_configuration.ts index 12e08869fa586..959a0c97acfa3 100644 --- a/x-pack/test/api_integration/apis/apm/agent_configuration.ts +++ b/x-pack/test/api_integration/apis/apm/agent_configuration.ts @@ -5,6 +5,7 @@ */ import expect from '@kbn/expect'; +import { AgentConfigurationIntake } from '../../../../plugins/apm/server/lib/settings/agent_configuration/configuration_types'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function agentConfigurationTests({ getService }: FtrProviderContext) { @@ -18,108 +19,122 @@ export default function agentConfigurationTests({ getService }: FtrProviderConte .set('kbn-xsrf', 'foo'); } - let createdConfigIds: any[] = []; - async function createConfiguration(configuration: any) { + async function createConfiguration(config: AgentConfigurationIntake) { + log.debug('creating configuration', config.service); const res = await supertest - .post(`/api/apm/settings/agent-configuration/new`) - .send(configuration) + .put(`/api/apm/settings/agent-configuration`) + .send(config) .set('kbn-xsrf', 'foo'); - createdConfigIds.push(res.body._id); + throwOnError(res); return res; } - function deleteCreatedConfigurations() { - const promises = Promise.all(createdConfigIds.map(deleteConfiguration)); - return promises; + async function updateConfiguration(config: AgentConfigurationIntake) { + log.debug('updating configuration', config.service); + const res = await supertest + .put(`/api/apm/settings/agent-configuration?overwrite=true`) + .send(config) + .set('kbn-xsrf', 'foo'); + + throwOnError(res); + + return res; } - function deleteConfiguration(configurationId: string) { - return supertest - .delete(`/api/apm/settings/agent-configuration/${configurationId}`) - .set('kbn-xsrf', 'foo') - .then((response: any) => { - createdConfigIds = createdConfigIds.filter(id => id === configurationId); - return response; - }); + async function deleteConfiguration({ service }: AgentConfigurationIntake) { + log.debug('deleting configuration', service); + const res = await supertest + .delete(`/api/apm/settings/agent-configuration`) + .send({ service }) + .set('kbn-xsrf', 'foo'); + + throwOnError(res); + + return res; + } + + function throwOnError(res: any) { + const { statusCode, req, body } = res; + if (statusCode !== 200) { + throw new Error(` + Endpoint: ${req.method} ${req.path} + Service: ${JSON.stringify(res.request._data.service)} + Status code: ${statusCode} + Response: ${body.message}`); + } } describe('agent configuration', () => { describe('when creating one configuration', () => { - let createdConfigId: string; + const newConfig = { + service: {}, + settings: { transaction_sample_rate: 0.55 }, + }; - const parameters = { + const searchParams = { service: { name: 'myservice', environment: 'development' }, etag: '7312bdcc34999629a3d39df24ed9b2a7553c0c39', }; before(async () => { - log.debug('creating agent configuration'); - - // all / all - const { body } = await createConfiguration({ - service: {}, - settings: { transaction_sample_rate: 0.1 }, - }); - - createdConfigId = body._id; + await createConfiguration(newConfig); }); - it('returns the created configuration', async () => { - const { statusCode, body } = await searchConfigurations(parameters); - + it('can find the created config', async () => { + const { statusCode, body } = await searchConfigurations(searchParams); expect(statusCode).to.equal(200); - expect(body._id).to.equal(createdConfigId); + expect(body._source.service).to.eql({}); + expect(body._source.settings).to.eql({ transaction_sample_rate: 0.55 }); }); - it('succesfully deletes the configuration', async () => { - await deleteConfiguration(createdConfigId); + it('can update the created config', async () => { + await updateConfiguration({ service: {}, settings: { transaction_sample_rate: 0.85 } }); - const { statusCode } = await searchConfigurations(parameters); + const { statusCode, body } = await searchConfigurations(searchParams); + expect(statusCode).to.equal(200); + expect(body._source.service).to.eql({}); + expect(body._source.settings).to.eql({ transaction_sample_rate: 0.85 }); + }); + it('can delete the created config', async () => { + await deleteConfiguration(newConfig); + const { statusCode } = await searchConfigurations(searchParams); expect(statusCode).to.equal(404); }); }); - describe('when creating four configurations', () => { - before(async () => { - log.debug('creating agent configuration'); - - // all / all - await createConfiguration({ + describe('when creating multiple configurations', () => { + const configs = [ + { service: {}, settings: { transaction_sample_rate: 0.1 }, - }); - - // my_service / all - await createConfiguration({ + }, + { service: { name: 'my_service' }, settings: { transaction_sample_rate: 0.2 }, - }); - - // all / production - await createConfiguration({ - service: { environment: 'production' }, + }, + { + service: { name: 'my_service', environment: 'development' }, settings: { transaction_sample_rate: 0.3 }, - }); - - // all / production - await createConfiguration({ - service: { environment: 'development' }, + }, + { + service: { environment: 'production' }, settings: { transaction_sample_rate: 0.4 }, - }); - - // my_service / production - await createConfiguration({ - service: { name: 'my_service', environment: 'development' }, + }, + { + service: { environment: 'development' }, settings: { transaction_sample_rate: 0.5 }, - }); + }, + ]; + + before(async () => { + await Promise.all(configs.map(config => createConfiguration(config))); }); after(async () => { - log.debug('deleting agent configurations'); - await deleteCreatedConfigurations(); + await Promise.all(configs.map(config => deleteConfiguration(config))); }); const agentsRequests = [ @@ -127,20 +142,24 @@ export default function agentConfigurationTests({ getService }: FtrProviderConte service: { name: 'non_existing_service', environment: 'non_existing_env' }, expectedSettings: { transaction_sample_rate: 0.1 }, }, + { + service: { name: 'my_service', environment: 'non_existing_env' }, + expectedSettings: { transaction_sample_rate: 0.2 }, + }, { service: { name: 'my_service', environment: 'production' }, expectedSettings: { transaction_sample_rate: 0.2 }, }, { - service: { name: 'non_existing_service', environment: 'production' }, + service: { name: 'my_service', environment: 'development' }, expectedSettings: { transaction_sample_rate: 0.3 }, }, { - service: { name: 'non_existing_service', environment: 'development' }, + service: { name: 'non_existing_service', environment: 'production' }, expectedSettings: { transaction_sample_rate: 0.4 }, }, { - service: { name: 'my_service', environment: 'development' }, + service: { name: 'non_existing_service', environment: 'development' }, expectedSettings: { transaction_sample_rate: 0.5 }, }, ]; @@ -159,18 +178,18 @@ export default function agentConfigurationTests({ getService }: FtrProviderConte }); describe('when an agent retrieves a configuration', () => { + const config = { + service: { name: 'myservice', environment: 'development' }, + settings: { transaction_sample_rate: 0.9 }, + }; + before(async () => { log.debug('creating agent configuration'); - - await createConfiguration({ - service: { name: 'myservice', environment: 'development' }, - settings: { transaction_sample_rate: 0.9 }, - }); + await createConfiguration(config); }); after(async () => { - log.debug('deleting agent configurations'); - await deleteCreatedConfigurations(); + await deleteConfiguration(config); }); it(`should have 'applied_by_agent=false' on first request`, async () => { diff --git a/x-pack/test/api_integration/apis/apm/feature_controls.ts b/x-pack/test/api_integration/apis/apm/feature_controls.ts index ec2bbca23ddd2..3c5314d0d3261 100644 --- a/x-pack/test/api_integration/apis/apm/feature_controls.ts +++ b/x-pack/test/api_integration/apis/apm/feature_controls.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -/* eslint-disable no-console */ - import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -14,8 +12,8 @@ export default function featureControlsTests({ getService }: FtrProviderContext) const supertestWithoutAuth = getService('supertestWithoutAuth'); const security = getService('security'); const spaces = getService('spaces'); - const log = getService('log'); const es = getService('legacyEs'); + const log = getService('log'); const start = encodeURIComponent(new Date(Date.now() - 10000).toISOString()); const end = encodeURIComponent(new Date().toISOString()); @@ -33,7 +31,7 @@ export default function featureControlsTests({ getService }: FtrProviderContext) interface Endpoint { req: { url: string; - method?: 'get' | 'post' | 'delete'; + method?: 'get' | 'post' | 'delete' | 'put'; body?: any; }; expectForbidden: (result: any) => void; @@ -148,7 +146,7 @@ export default function featureControlsTests({ getService }: FtrProviderContext) index: '.apm-agent-configuration', }); - console.warn(JSON.stringify(res, null, 2)); + log.error(JSON.stringify(res, null, 2)); }, }, ]; @@ -196,7 +194,7 @@ export default function featureControlsTests({ getService }: FtrProviderContext) const { statusCode, req } = response; if (statusCode !== 200) { - log.debug(`Endpoint: ${req.method} ${req.path} + throw new Error(`Endpoint: ${req.method} ${req.path} Status code: ${statusCode} Response: ${response.body.message}`); } @@ -216,9 +214,9 @@ export default function featureControlsTests({ getService }: FtrProviderContext) spaceId?: string; }) { for (const endpoint of endpoints) { - console.log(`Requesting: ${endpoint.req.url}. Expecting: ${expectation}`); + log.info(`Requesting: ${endpoint.req.url}. Expecting: ${expectation}`); const result = await executeAsUser(endpoint.req, username, password, spaceId); - console.log(`Responded: ${endpoint.req.url}`); + log.info(`Responded: ${endpoint.req.url}`); try { if (expectation === 'forbidden') { @@ -244,26 +242,28 @@ export default function featureControlsTests({ getService }: FtrProviderContext) } describe('apm feature controls', () => { - let res: any; + const config = { + service: { name: 'test-service' }, + settings: { transaction_sample_rate: 0.5 }, + }; before(async () => { - console.log(`Creating agent configuration`); - res = await executeAsAdmin({ - method: 'post', - url: '/api/apm/settings/agent-configuration/new', - body: { - service: { name: 'test-service' }, - settings: { transaction_sample_rate: 0.5 }, - }, + log.info(`Creating agent configuration`); + await executeAsAdmin({ + method: 'put', + url: '/api/apm/settings/agent-configuration', + body: config, }); - console.log(`Agent configuration created`); + log.info(`Agent configuration created`); }); after(async () => { - console.log('deleting agent configuration'); - const configurationId = res.body._id; + log.info('deleting agent configuration'); await executeAsAdmin({ method: 'delete', - url: `/api/apm/settings/agent-configuration/${configurationId}`, + url: `/api/apm/settings/agent-configuration`, + body: { + service: config.service, + }, }); }); diff --git a/x-pack/test/api_integration/apis/apm/index.ts b/x-pack/test/api_integration/apis/apm/index.ts index c49d577537048..6f41f4abfecc3 100644 --- a/x-pack/test/api_integration/apis/apm/index.ts +++ b/x-pack/test/api_integration/apis/apm/index.ts @@ -7,7 +7,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function apmApiIntegrationTests({ loadTestFile }: FtrProviderContext) { - describe('APM', () => { + describe('APM specs', () => { loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./agent_configuration')); }); diff --git a/x-pack/test/functional/apps/apm/index.ts b/x-pack/test/functional/apps/apm/index.ts index 945af09183f03..bf254f9b9b419 100644 --- a/x-pack/test/functional/apps/apm/index.ts +++ b/x-pack/test/functional/apps/apm/index.ts @@ -6,7 +6,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function({ loadTestFile }: FtrProviderContext) { - describe('APM', function() { + describe('APM specs', function() { this.tags('ciGroup6'); loadTestFile(require.resolve('./feature_controls')); }); From 5eefdbb84266e2af1998c35d4876f18bc13d1fe0 Mon Sep 17 00:00:00 2001 From: Andrew Cholakian Date: Mon, 24 Feb 2020 16:46:58 -0600 Subject: [PATCH 035/123] [Uptime] Use scripted metric for snapshot calculation (#58247) (#58389) Fixes #58079 This is an improved version of #58078 Note, this is a bugfix targeting 7.6.1 . I've decided to open this PR directly against 7.6 in the interest of time. We can forward-port this to 7.x / master later. This patch improves the handling of timespans with snapshot counts. This feature originally worked, but suffered a regression when we increased the default timespan in the query context to 5m. This means that without this patch the counts you get are the maximum total number of monitors that were down over the past 5m, which is not really that useful. We now use a scripted metric to always count precisely the number of up/down monitors. On my box this could process 400k summary docs in ~600ms. This should scale as shards are added. I attempted to keep memory usage relatively slow by using simple maps of strings. --- .../lib/requests/get_snapshot_counts.ts | 194 +++++++++++++----- .../apis/uptime/rest/snapshot.ts | 105 +++++----- 2 files changed, 192 insertions(+), 107 deletions(-) diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_snapshot_counts.ts b/x-pack/legacy/plugins/uptime/server/lib/requests/get_snapshot_counts.ts index 6236971146015..8d84c0f4d6769 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_snapshot_counts.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/requests/get_snapshot_counts.ts @@ -6,7 +6,7 @@ import { UMElasticsearchQueryFn } from '../adapters'; import { Snapshot } from '../../../common/runtime_types'; -import { QueryContext, MonitorGroupIterator } from './search'; +import { QueryContext } from './search'; import { CONTEXT_DEFAULTS, INDEX_NAMES } from '../../../common/constants'; export interface GetSnapshotCountParams { @@ -16,49 +16,6 @@ export interface GetSnapshotCountParams { statusFilter?: string; } -const fastStatusCount = async (context: QueryContext): Promise => { - const params = { - index: INDEX_NAMES.HEARTBEAT, - body: { - size: 0, - query: { bool: { filter: await context.dateAndCustomFilters() } }, - aggs: { - unique: { - // We set the precision threshold to 40k which is the max precision supported by cardinality - cardinality: { field: 'monitor.id', precision_threshold: 40000 }, - }, - down: { - filter: { range: { 'summary.down': { gt: 0 } } }, - aggs: { - unique: { cardinality: { field: 'monitor.id', precision_threshold: 40000 } }, - }, - }, - }, - }, - }; - - const statistics = await context.search(params); - const total = statistics.aggregations.unique.value; - const down = statistics.aggregations.down.unique.value; - - return { - total, - down, - up: total - down, - }; -}; - -const slowStatusCount = async (context: QueryContext, status: string): Promise => { - const downContext = context.clone(); - downContext.statusFilter = status; - const iterator = new MonitorGroupIterator(downContext); - let count = 0; - while (await iterator.next()) { - count++; - } - return count; -}; - export const getSnapshotCount: UMElasticsearchQueryFn = async ({ callES, dateRangeStart, @@ -81,18 +38,7 @@ export const getSnapshotCount: UMElasticsearchQueryFn = - counts.up > counts.down ? ['down', 'up'] : ['up', 'down']; - counts[leastCommonStatus] = await slowStatusCount(context, leastCommonStatus); - counts[mostCommonStatus] = counts.total - counts[leastCommonStatus]; - } + const counts = await statusCount(context); return { total: statusFilter ? counts[statusFilter] : counts.total, @@ -100,3 +46,139 @@ export const getSnapshotCount: UMElasticsearchQueryFn => { + const res = await context.search({ + index: INDEX_NAMES.HEARTBEAT, + body: statusCountBody(await context.dateAndCustomFilters()), + }); + + return res.aggregations.counts.value; +}; + +const statusCountBody = (filters: any): any => { + return { + size: 0, + query: { + bool: { + filter: [ + { + exists: { + field: 'summary', + }, + }, + filters, + ], + }, + }, + aggs: { + counts: { + scripted_metric: { + init_script: 'state.locStatus = new HashMap(); state.totalDocs = 0;', + map_script: ` + def loc = doc["observer.geo.name"].size() == 0 ? "" : doc["observer.geo.name"][0]; + + // One concern here is memory since we could build pretty gigantic maps. I've opted to + // stick to a simple map to reduce memory overhead. This means we do + // a little string parsing to treat these strings as records that stay lexicographically + // sortable (which is important later). + // We encode the ID and location as $id.len:$id$loc + String id = doc["monitor.id"][0]; + String idLenDelim = Integer.toHexString(id.length()) + ":" + id; + String idLoc = loc == null ? idLenDelim : idLenDelim + loc; + + String status = doc["summary.down"][0] > 0 ? "d" : "u"; + String timeAndStatus = doc["@timestamp"][0].toInstant().toEpochMilli().toString() + status; + state.locStatus[idLoc] = timeAndStatus; + state.totalDocs++; + `, + combine_script: ` + return state; + `, + reduce_script: ` + // Use a treemap since it's traversable in sorted order. + // This is important later. + TreeMap locStatus = new TreeMap(); + long totalDocs = 0; + int uniqueIds = 0; + for (state in states) { + totalDocs += state.totalDocs; + for (entry in state.locStatus.entrySet()) { + // Update the value for the given key if we have a more recent check from this location. + locStatus.merge(entry.getKey(), entry.getValue(), (a,b) -> a.compareTo(b) > 0 ? a : b) + } + } + + HashMap locTotals = new HashMap(); + int total = 0; + int down = 0; + String curId = ""; + boolean curIdDown = false; + // We now iterate through our tree map in order, which means records for a given ID + // always are encountered one after the other. This saves us having to make an intermediate + // map. + for (entry in locStatus.entrySet()) { + String idLoc = entry.getKey(); + String timeStatus = entry.getValue(); + + // Parse the length delimited id/location strings described in the map section + int colonIndex = idLoc.indexOf(":"); + int idEnd = Integer.parseInt(idLoc.substring(0, colonIndex), 16) + colonIndex + 1; + String id = idLoc.substring(colonIndex + 1, idEnd); + String loc = idLoc.substring(idEnd, idLoc.length()); + String status = timeStatus.substring(timeStatus.length() - 1); + + // Here we increment counters for the up/down key per location + // We also create a new hashmap in locTotals if we've never seen this location + // before. + locTotals.compute(loc, (k,v) -> { + HashMap res = v; + if (v == null) { + res = new HashMap(); + res.put('up', 0); + res.put('down', 0); + } + + if (status == 'u') { + res.up++; + } else { + res.down++; + } + + return res; + }); + + + // We've encountered a new ID + if (curId != id) { + total++; + curId = id; + if (status == "d") { + curIdDown = true; + down++; + } else { + curIdDown = false; + } + } else if (!curIdDown) { + if (status == "d") { + curIdDown = true; + down++; + } else { + curIdDown = false; + } + } + } + + Map result = new HashMap(); + result.total = total; + result.location_totals = locTotals; + result.up = total - down; + result.down = down; + result.totalDocs = totalDocs; + return result; + `, + }, + }, + }, + }; +}; diff --git a/x-pack/test/api_integration/apis/uptime/rest/snapshot.ts b/x-pack/test/api_integration/apis/uptime/rest/snapshot.ts index b0d97837c770f..20fe59d149ae8 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/snapshot.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/snapshot.ts @@ -34,66 +34,69 @@ export default function({ getService }: FtrProviderContext) { let dateRange: { start: string; end: string }; [true, false].forEach(async (includeTimespan: boolean) => { - describe(`with timespans ${includeTimespan ? 'included' : 'missing'}`, async () => { - before(async () => { - const promises: Array> = []; - - // When includeTimespan is false we have to remove the values there. - let mogrify = (d: any) => d; - if ((includeTimespan = false)) { - mogrify = (d: any): any => { - d.monitor.delete('timespan'); + [true, false].forEach(async (includeObserver: boolean) => { + describe(`with timespans=${includeTimespan} and observer=${includeObserver}`, async () => { + before(async () => { + const promises: Array> = []; + + const mogrify = (d: any) => { + if (!includeTimespan) { + delete d.monitor.timespan; + } + if (!includeObserver) { + delete d.observer; + } return d; }; - } - - const makeMonitorChecks = async (monitorId: string, status: 'up' | 'down') => { - return makeChecksWithStatus( - getService('legacyEs'), - monitorId, - checksPerMonitor, - numIps, - scheduleEvery, - {}, - status, - mogrify - ); - }; - for (let i = 0; i < numUpMonitors; i++) { - promises.push(makeMonitorChecks(`up-${i}`, 'up')); - } - for (let i = 0; i < numDownMonitors; i++) { - promises.push(makeMonitorChecks(`down-${i}`, 'down')); - } + const makeMonitorChecks = async (monitorId: string, status: 'up' | 'down') => { + return makeChecksWithStatus( + getService('legacyEs'), + monitorId, + checksPerMonitor, + numIps, + scheduleEvery, + {}, + status, + mogrify + ); + }; - const allResults = await Promise.all(promises); - dateRange = getChecksDateRange(allResults); - }); + for (let i = 0; i < numUpMonitors; i++) { + promises.push(makeMonitorChecks(`up-${i}`, 'up')); + } + for (let i = 0; i < numDownMonitors; i++) { + promises.push(makeMonitorChecks(`down-${i}`, 'down')); + } - it('will count all statuses correctly', async () => { - const apiResponse = await supertest.get( - `/api/uptime/snapshot/count?dateRangeStart=${dateRange.start}&dateRangeEnd=${dateRange.end}` - ); + const allResults = await Promise.all(promises); + dateRange = getChecksDateRange(allResults); + }); - expectFixtureEql(apiResponse.body, 'snapshot'); - }); + it('will count all statuses correctly', async () => { + const apiResponse = await supertest.get( + `/api/uptime/snapshot/count?dateRangeStart=${dateRange.start}&dateRangeEnd=${dateRange.end}` + ); - it('will fetch a monitor snapshot filtered by down status', async () => { - const statusFilter = 'down'; - const apiResponse = await supertest.get( - `/api/uptime/snapshot/count?dateRangeStart=${dateRange.start}&dateRangeEnd=${dateRange.end}&statusFilter=${statusFilter}` - ); + expectFixtureEql(apiResponse.body, 'snapshot'); + }); - expectFixtureEql(apiResponse.body, 'snapshot_filtered_by_down'); - }); + it('will fetch a monitor snapshot filtered by down status', async () => { + const statusFilter = 'down'; + const apiResponse = await supertest.get( + `/api/uptime/snapshot/count?dateRangeStart=${dateRange.start}&dateRangeEnd=${dateRange.end}&statusFilter=${statusFilter}` + ); - it('will fetch a monitor snapshot filtered by up status', async () => { - const statusFilter = 'up'; - const apiResponse = await supertest.get( - `/api/uptime/snapshot/count?dateRangeStart=${dateRange.start}&dateRangeEnd=${dateRange.end}&statusFilter=${statusFilter}` - ); - expectFixtureEql(apiResponse.body, 'snapshot_filtered_by_up'); + expectFixtureEql(apiResponse.body, 'snapshot_filtered_by_down'); + }); + + it('will fetch a monitor snapshot filtered by up status', async () => { + const statusFilter = 'up'; + const apiResponse = await supertest.get( + `/api/uptime/snapshot/count?dateRangeStart=${dateRange.start}&dateRangeEnd=${dateRange.end}&statusFilter=${statusFilter}` + ); + expectFixtureEql(apiResponse.body, 'snapshot_filtered_by_up'); + }); }); }); }); From a00ebc6f187ffbd920b0e2bf3f92483239ed0c0f Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Mon, 24 Feb 2020 18:44:52 -0500 Subject: [PATCH 036/123] [Uptime] Delete useless try...catch blocks (#58263) * Delete useless try...catch blocks. * Delete unneeded function. Co-authored-by: Elastic Machine --- .../plugins/uptime/public/hooks/use_telemetry.ts | 10 +++------- .../plugins/uptime/server/lib/helper/index.ts | 1 - .../uptime/server/lib/helper/parse_filter_query.ts | 13 ------------- .../server/lib/requests/get_ping_histogram.ts | 4 ++-- 4 files changed, 5 insertions(+), 23 deletions(-) delete mode 100644 x-pack/legacy/plugins/uptime/server/lib/helper/parse_filter_query.ts diff --git a/x-pack/legacy/plugins/uptime/public/hooks/use_telemetry.ts b/x-pack/legacy/plugins/uptime/public/hooks/use_telemetry.ts index 15f276174e2cf..7eb18404decfd 100644 --- a/x-pack/legacy/plugins/uptime/public/hooks/use_telemetry.ts +++ b/x-pack/legacy/plugins/uptime/public/hooks/use_telemetry.ts @@ -22,13 +22,9 @@ const getApiPath = (page?: UptimePage) => { }; const logPageLoad = async (fetch: HttpHandler, page?: UptimePage) => { - try { - await fetch(getApiPath(page), { - method: 'POST', - }); - } catch (e) { - throw e; - } + await fetch(getApiPath(page), { + method: 'POST', + }); }; export const useUptimeTelemetry = (page?: UptimePage) => { diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/index.ts b/x-pack/legacy/plugins/uptime/server/lib/helper/index.ts index 0dcbc0a424b5e..1607c36f1d1b7 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/helper/index.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/helper/index.ts @@ -7,6 +7,5 @@ export { getFilterClause } from './get_filter_clause'; export { parseRelativeDate } from './get_histogram_interval'; export { getHistogramIntervalFormatted } from './get_histogram_interval_formatted'; -export { parseFilterQuery } from './parse_filter_query'; export { assertCloseTo } from './assert_close_to'; export { objectValuesToArrays } from './object_to_array'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/parse_filter_query.ts b/x-pack/legacy/plugins/uptime/server/lib/helper/parse_filter_query.ts deleted file mode 100644 index 4c73ec53af9b9..0000000000000 --- a/x-pack/legacy/plugins/uptime/server/lib/helper/parse_filter_query.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export const parseFilterQuery = (query?: string | null) => { - try { - return query ? JSON.parse(query) : null; - } catch { - return null; - } -}; diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_ping_histogram.ts b/x-pack/legacy/plugins/uptime/server/lib/requests/get_ping_histogram.ts index 3b448dc31659b..7b8ca4708255c 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_ping_histogram.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/requests/get_ping_histogram.ts @@ -5,7 +5,7 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { parseFilterQuery, getFilterClause } from '../helper'; +import { getFilterClause } from '../helper'; import { INDEX_NAMES, QUERY } from '../../../common/constants'; import { HistogramQueryResult } from './types'; import { HistogramResult } from '../../../common/types'; @@ -27,7 +27,7 @@ export const getPingHistogram: UMElasticsearchQueryFn< GetPingHistogramParams, HistogramResult > = async ({ callES, from, to, filters, monitorId, statusFilter }) => { - const boolFilters = parseFilterQuery(filters); + const boolFilters = filters ? JSON.parse(filters) : null; const additionalFilters = []; if (monitorId) { additionalFilters.push({ match: { 'monitor.id': monitorId } }); From 33334132eaacde693caa3f7b6a337309abd784bb Mon Sep 17 00:00:00 2001 From: Spencer Date: Mon, 24 Feb 2020 17:07:36 -0700 Subject: [PATCH 037/123] [kbn/optimizer] disable parallelization in terser plugin (#58396) * [kbn/optimizer] disable parallelization in terer plugin * use more workers when building the dist --- .../kbn-optimizer/src/optimizer/optimizer_config.ts | 11 ++++++++++- packages/kbn-optimizer/src/worker/webpack.config.ts | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer/optimizer_config.ts index a258e1010fce3..1c8ae265bf6bb 100644 --- a/packages/kbn-optimizer/src/optimizer/optimizer_config.ts +++ b/packages/kbn-optimizer/src/optimizer/optimizer_config.ts @@ -25,6 +25,15 @@ import { Bundle, WorkerConfig } from '../common'; import { findKibanaPlatformPlugins, KibanaPlatformPlugin } from './kibana_platform_plugins'; import { getBundles } from './get_bundles'; +function pickMaxWorkerCount(dist: boolean) { + // don't break if cpus() returns nothing, or an empty array + const cpuCount = Math.max(Os.cpus()?.length, 1); + // if we're buiding the dist then we can use more of the system's resources to get things done a little quicker + const maxWorkers = dist ? cpuCount - 1 : Math.ceil(cpuCount / 3); + // ensure we always have at least two workers + return Math.max(maxWorkers, 2); +} + interface Options { /** absolute path to root of the repo/build */ repoRoot: string; @@ -110,7 +119,7 @@ export class OptimizerConfig { const maxWorkerCount = process.env.KBN_OPTIMIZER_MAX_WORKERS ? parseInt(process.env.KBN_OPTIMIZER_MAX_WORKERS, 10) - : options.maxWorkerCount ?? Math.max(Math.ceil(Math.max(Os.cpus()?.length, 1) / 3), 2); + : options.maxWorkerCount ?? pickMaxWorkerCount(dist); if (typeof maxWorkerCount !== 'number' || !Number.isFinite(maxWorkerCount)) { throw new TypeError('worker count must be a number'); } diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 22b927d4638d7..3c6ae78bc4d91 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -252,6 +252,7 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) { cache: false, sourceMap: false, extractComments: false, + parallel: false, terserOptions: { compress: false, mangle: false, From 277b38079ee55a5ae088a3a4c6bacf127f5c8968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Tue, 25 Feb 2020 13:12:27 +0530 Subject: [PATCH 038/123] [Index management] Move to new platform "plugins" folder (#58109) --- x-pack/.i18nrc.json | 2 +- .../cross_cluster_replication/index.js | 7 +- .../components/detail_panel/detail_panel.js | 2 +- .../components/detail_panel/detail_panel.js | 7 +- .../public/extend_index_management/index.js | 9 ++- .../__jest__/extend_index_management.test.js | 6 +- .../index_lifecycle_management/plugin.ts | 8 +- .../public/legacy.ts | 4 +- .../components/policy_table/policy_table.js | 2 +- .../np_ready/extend_index_management/index.js | 3 +- .../legacy/plugins/index_management/index.ts | 29 +------ .../index_management/public/index.html | 3 - .../legacy/plugins/remote_clusters/index.ts | 4 +- x-pack/legacy/plugins/rollup/index.ts | 4 +- x-pack/legacy/plugins/rollup/public/legacy.ts | 2 - x-pack/legacy/plugins/rollup/public/plugin.ts | 20 +++-- x-pack/legacy/plugins/rollup/server/plugin.ts | 10 +-- .../rollup/server/rollup_data_enricher.ts | 7 +- x-pack/legacy/plugins/rollup/server/types.ts | 1 - .../client_integration/helpers/constants.ts | 0 .../helpers/home.helpers.ts | 6 +- .../helpers/http_requests.ts | 0 .../client_integration/helpers/index.ts | 2 +- .../helpers/setup_environment.tsx | 3 +- .../helpers/template_clone.helpers.ts | 4 +- .../helpers/template_create.helpers.ts | 4 +- .../helpers/template_edit.helpers.ts | 4 +- .../helpers/template_form.helpers.ts | 2 +- .../__jest__/client_integration/home.test.ts | 0 .../template_clone.test.tsx | 0 .../template_create.test.tsx | 0 .../client_integration/template_edit.test.tsx | 0 .../__snapshots__/index_table.test.js.snap | 0 .../__jest__/components/index_table.test.js | 4 +- .../__snapshots__/flatten_object.test.js.snap | 0 .../__jest__/lib/flatten_object.test.js | 0 .../plugins/index_management/__mocks__/ace.js | 0 .../__mocks__/ui/documentation_links.js | 0 .../index_management/__mocks__/ui/notify.js | 0 .../common/constants/api_base_path.ts | 0 .../common/constants/base_path.ts | 0 .../common/constants/index.ts | 0 .../common/constants/index_statuses.ts | 0 .../common/constants/invalid_characters.ts | 0 .../common/constants/plugin.ts | 2 +- .../common/constants/ui_metric.ts | 0 .../plugins/index_management/common/index.ts | 0 .../index_management/common/lib/index.ts | 0 .../common/lib/template_serialization.ts | 0 .../index_management/common/types/index.ts | 0 .../common/types/templates.ts | 0 x-pack/plugins/index_management/kibana.json | 15 ++++ .../public/application/app.tsx | 2 +- .../public/application/app_context.tsx | 4 +- .../public/application/components/index.ts | 0 .../client_integration/helpers/index.ts | 2 +- .../helpers/mappings_editor.helpers.ts | 2 +- .../mappings_editor.test.tsx | 0 .../components/mappings_editor/_index.scss | 0 .../mappings_editor/components/_index.scss | 0 .../mappings_editor/components/code_block.tsx | 0 .../configuration_form/configuration_form.tsx | 6 +- .../configuration_form_schema.tsx | 0 .../dynamic_mapping_section.tsx | 0 .../dynamic_mapping_section/index.ts | 0 .../components/configuration_form/index.ts | 0 .../meta_field_section/index.ts | 0 .../meta_field_section/meta_field_section.tsx | 0 .../configuration_form/routing_section.tsx | 0 .../source_field_section/index.ts | 0 .../source_field_section.tsx | 0 .../components/document_fields/_index.scss | 0 .../document_fields/document_fields.tsx | 11 ++- .../document_fields_header.tsx | 0 .../editor_toggle_controls.tsx | 0 .../field_parameters/analyzer_parameter.tsx | 0 .../analyzer_parameter_selects.tsx | 20 +++-- .../field_parameters/analyzers_parameter.tsx | 0 .../field_parameters/boost_parameter.tsx | 0 .../coerce_number_parameter.tsx | 0 .../coerce_shape_parameter.tsx | 0 .../field_parameters/copy_to_parameter.tsx | 0 .../field_parameters/doc_values_parameter.tsx | 0 .../field_parameters/dynamic_parameter.tsx | 0 .../eager_global_ordinals_parameter.tsx | 0 .../field_parameters/enabled_parameter.tsx | 0 .../fielddata_frequency_filter_absolute.tsx | 0 .../fielddata_frequency_filter_percentage.tsx | 0 .../field_parameters/fielddata_parameter.tsx | 0 .../field_parameters/format_parameter.tsx | 0 .../field_parameters/ignore_malformed.tsx | 0 .../ignore_z_value_parameter.tsx | 0 .../document_fields/field_parameters/index.ts | 0 .../field_parameters/index_parameter.tsx | 0 .../field_parameters/locale_parameter.tsx | 0 .../max_shingle_size_parameter.tsx | 0 .../field_parameters/name_parameter.tsx | 0 .../field_parameters/norms_parameter.tsx | 0 .../field_parameters/null_value_parameter.tsx | 0 .../orientation_parameter.tsx | 0 .../field_parameters/path_parameter.tsx | 0 .../field_parameters/relations_parameter.tsx | 0 .../field_parameters/similarity_parameter.tsx | 0 .../split_queries_on_whitespace_parameter.tsx | 0 .../field_parameters/store_parameter.tsx | 0 .../term_vector_parameter.tsx | 0 .../field_parameters/type_parameter.tsx | 0 .../fields/_field_list_item.scss | 0 .../document_fields/fields/_index.scss | 0 .../fields/create_field/create_field.tsx | 80 +++++++++++-------- .../fields/create_field/index.ts | 0 .../required_parameters_forms/alias_type.tsx | 0 .../dense_vector_type.tsx | 0 .../required_parameters_forms/index.ts | 0 .../scaled_float_type.tsx | 0 .../token_count_type.tsx | 0 .../fields/delete_field_provider.tsx | 0 .../edit_field/_edit_field_form_row.scss | 0 .../fields/edit_field/_index.scss | 0 .../advanced_parameters_section.tsx | 0 .../edit_field/basic_parameters_section.tsx | 0 .../fields/edit_field/edit_field.tsx | 0 .../edit_field/edit_field_container.tsx | 4 +- .../fields/edit_field/edit_field_form_row.tsx | 0 .../edit_field/edit_field_header_form.tsx | 0 .../edit_field/field_description_section.tsx | 0 .../fields/edit_field/index.ts | 0 .../edit_field/update_field_provider.tsx | 0 .../fields/field_types/alias_type.tsx | 0 .../fields/field_types/binary_type.tsx | 0 .../fields/field_types/boolean_type.tsx | 0 .../fields/field_types/completion_type.tsx | 0 .../fields/field_types/date_type.tsx | 0 .../fields/field_types/dense_vector_type.tsx | 0 .../fields/field_types/flattened_type.tsx | 0 .../fields/field_types/geo_point_type.tsx | 0 .../fields/field_types/geo_shape_type.tsx | 0 .../fields/field_types/index.ts | 0 .../fields/field_types/ip_type.tsx | 0 .../fields/field_types/join_type.tsx | 0 .../fields/field_types/keyword_type.tsx | 0 .../fields/field_types/nested_type.tsx | 0 .../fields/field_types/numeric_type.tsx | 0 .../fields/field_types/object_type.tsx | 0 .../fields/field_types/range_type.tsx | 0 .../fields/field_types/search_as_you_type.tsx | 0 .../fields/field_types/shape_type.tsx | 0 .../fields/field_types/text_type.tsx | 0 .../fields/field_types/token_count_type.tsx | 0 .../document_fields/fields/fields_list.tsx | 0 .../fields/fields_list_item.tsx | 0 .../fields/fields_list_item_container.tsx | 10 +-- .../document_fields/fields/index.ts | 0 .../modal_confirmation_delete_fields.tsx | 0 .../document_fields/fields_json_editor.tsx | 0 .../document_fields/fields_tree_editor.tsx | 12 +-- .../components/document_fields/index.ts | 0 .../document_fields/search_fields/index.ts | 0 .../search_fields/search_result.tsx | 0 .../search_fields/search_result_item.tsx | 0 .../components/fields_tree.tsx | 0 .../mappings_editor/components/index.ts | 0 .../components/load_mappings/index.ts | 0 .../load_mappings/load_from_json_button.tsx | 0 .../load_mappings_provider.test.tsx | 2 +- .../load_mappings/load_mappings_provider.tsx | 0 .../components/multiple_mappings_warning.tsx | 0 .../components/templates_form/index.ts | 0 .../templates_form/templates_form.tsx | 6 +- .../templates_form/templates_form_schema.ts | 0 .../mappings_editor/components/tree/index.ts | 0 .../mappings_editor/components/tree/tree.tsx | 0 .../components/tree/tree_item.tsx | 0 .../constants/data_types_definition.tsx | 0 .../constants/default_values.ts | 0 .../constants/field_options.tsx | 0 .../constants/field_options_i18n.ts | 0 .../mappings_editor/constants/index.ts | 0 .../constants/mappings_editor.ts | 0 .../constants/parameters_definition.tsx | 0 .../components/mappings_editor/index.ts | 0 .../index_settings_context.tsx | 0 .../mappings_editor/lib/error_reporter.ts | 0 .../lib/extract_mappings_definition.test.ts | 0 .../lib/extract_mappings_definition.ts | 0 .../components/mappings_editor/lib/index.ts | 0 .../lib/mappings_validator.test.ts | 0 .../mappings_editor/lib/mappings_validator.ts | 0 .../mappings_editor/lib/search_fields.test.ts | 0 .../mappings_editor/lib/search_fields.tsx | 0 .../mappings_editor/lib/serializers.ts | 0 .../mappings_editor/lib/utils.test.ts | 0 .../components/mappings_editor/lib/utils.ts | 0 .../mappings_editor/lib/validators.ts | 0 .../mappings_editor/mappings_editor.tsx | 2 +- .../mappings_editor/mappings_state.tsx | 4 +- .../components/mappings_editor/reducer.ts | 0 .../mappings_editor/shared_imports.ts | 8 +- .../components/mappings_editor/types.ts | 0 .../application/components/no_match/index.ts | 0 .../components/no_match/no_match.tsx | 0 .../components/page_error/index.ts | 0 .../page_error/page_error_forbidden.tsx | 0 .../application/components/section_error.tsx | 0 .../components/section_loading.tsx | 0 .../components/template_delete_modal.tsx | 0 .../components/template_form/index.ts | 0 .../components/template_form/steps/index.ts | 0 .../template_form/steps/step_aliases.tsx | 0 .../template_form/steps/step_logistics.tsx | 15 +--- .../template_form/steps/step_mappings.tsx | 0 .../template_form/steps/step_review.tsx | 2 +- .../template_form/steps/step_settings.tsx | 0 .../template_form/steps/use_json_step.ts | 14 ++-- .../template_form/template_form.tsx | 34 ++++---- .../template_form/template_form_schemas.tsx | 5 +- .../template_form/template_steps.tsx | 0 .../components/template_form/types.ts | 0 .../constants/detail_panel_tabs.ts | 0 .../public/application/constants/index.ts | 0 .../constants/refresh_intervals.ts | 0 .../public/application/index.tsx | 2 +- .../public/application/lib/ace.js | 6 +- .../public/application/lib/edit_settings.js | 0 .../public/application/lib/flatten_object.js | 0 .../application/lib/flatten_panel_tree.js | 0 .../application/lib/index_status_labels.js | 0 .../lib/manage_angular_lifecycle.ts | 0 .../public/application/lib/render_badges.js | 0 .../public/application/sections/home/home.tsx | 0 .../public/application/sections/home/index.ts | 0 .../detail_panel/detail_panel.container.js | 0 .../index_list/detail_panel/detail_panel.js | 0 .../edit_settings_json.container.js | 0 .../edit_settings_json/edit_settings_json.js | 0 .../detail_panel/edit_settings_json/index.js | 0 .../home/index_list/detail_panel/index.js | 0 .../detail_panel/show_json/index.js | 0 .../show_json/show_json.container.js | 0 .../detail_panel/show_json/show_json.js | 0 .../index_list/detail_panel/summary/index.js | 0 .../detail_panel/summary/summary.container.js | 0 .../detail_panel/summary/summary.js | 0 .../sections/home/index_list/index.ts | 0 .../index_actions_context_menu/index.js | 0 .../index_actions_context_menu.container.js | 0 .../index_actions_context_menu.js | 0 .../sections/home/index_list/index_list.d.ts | 0 .../sections/home/index_list/index_list.js | 0 .../home/index_list/index_table/index.js | 0 .../index_table/index_table.container.js | 0 .../index_list/index_table/index_table.js | 0 .../sections/home/template_list/index.ts | 0 .../template_list/template_details/index.ts | 0 .../template_details/tabs/index.ts | 0 .../template_details/tabs/tab_aliases.tsx | 0 .../template_details/tabs/tab_mappings.tsx | 0 .../template_details/tabs/tab_settings.tsx | 0 .../template_details/tabs/tab_summary.tsx | 0 .../template_details/template_details.tsx | 4 +- .../home/template_list/template_list.tsx | 6 +- .../template_list/template_table/index.ts | 0 .../template_table/template_table.tsx | 0 .../sections/template_clone/index.ts | 0 .../template_clone/template_clone.tsx | 4 +- .../sections/template_create/index.ts | 0 .../template_create/template_create.tsx | 0 .../sections/template_edit/index.ts | 0 .../sections/template_edit/template_edit.tsx | 4 +- .../public/application/services/api.ts | 4 +- .../application/services/breadcrumbs.ts | 2 +- .../application/services/documentation.ts | 2 +- .../application/services/health_to_color.ts | 0 .../public/application/services/http.ts | 2 +- .../public/application/services/index.ts | 2 +- .../public/application/services/navigation.ts | 0 .../application/services/notification.ts | 2 +- .../public/application/services/routing.ts | 0 .../public/application/services/sort_table.ts | 0 .../public/application/services/ui_metric.ts | 6 +- .../application/services/use_request.ts | 0 .../store/actions/clear_cache_indices.js | 0 .../store/actions/clear_row_status.js | 0 .../store/actions/close_indices.js | 0 .../store/actions/delete_indices.js | 0 .../application/store/actions/detail_panel.js | 0 .../store/actions/edit_index_settings.js | 0 .../store/actions/extension_action.js | 0 .../store/actions/flush_indices.js | 0 .../store/actions/forcemerge_indices.js | 0 .../store/actions/freeze_indices.js | 0 .../public/application/store/actions/index.js | 0 .../store/actions/load_index_data.js | 0 .../application/store/actions/load_indices.js | 0 .../application/store/actions/open_indices.js | 0 .../store/actions/refresh_indices.js | 0 .../store/actions/reload_indices.js | 0 .../application/store/actions/table_state.js | 0 .../store/actions/unfreeze_indices.js | 0 .../store/actions/update_index_settings.js | 0 .../public/application/store/index.ts | 0 .../store/reducers/detail_panel.js | 0 .../application/store/reducers/index.js | 0 .../store/reducers/index_management.js | 0 .../application/store/reducers/indices.js | 0 .../application/store/reducers/row_status.js | 0 .../application/store/reducers/table_state.js | 0 .../application/store/selectors/index.d.ts | 0 .../application/store/selectors/index.js | 0 .../public/application/store/store.d.ts | 0 .../public/application/store/store.js | 0 .../index_management/public/index.scss | 0 .../plugins/index_management/public/index.ts | 11 +-- .../plugins/index_management/public/mocks.ts | 0 .../plugins/index_management/public/plugin.ts | 10 +-- .../services/extensions_service.mock.ts | 0 .../public/services/extensions_service.ts | 0 .../index_management/public/services/index.ts | 0 .../index_management/public/shared_imports.ts | 33 ++++++++ .../plugins/index_management/public/types.ts | 0 .../index_management/server/config.ts} | 14 ++-- .../plugins/index_management/server/index.ts | 10 +++ .../server/lib/fetch_aliases.test.ts | 0 .../server/lib/fetch_aliases.ts | 0 .../server/lib/fetch_indices.ts | 0 .../server/lib/get_managed_templates.ts | 0 .../server/lib/is_es_error.ts | 0 .../plugins/index_management/server/plugin.ts | 4 +- .../server/routes/api/index.ts | 0 .../server/routes/api/indices/index.ts | 0 .../api/indices/register_clear_cache_route.ts | 0 .../api/indices/register_close_route.ts | 0 .../api/indices/register_delete_route.ts | 0 .../api/indices/register_flush_route.ts | 0 .../api/indices/register_forcemerge_route.ts | 0 .../api/indices/register_freeze_route.ts | 0 .../api/indices/register_indices_routes.ts | 0 .../routes/api/indices/register_list_route.ts | 0 .../routes/api/indices/register_open_route.ts | 0 .../api/indices/register_refresh_route.ts | 0 .../api/indices/register_reload_route.ts | 0 .../api/indices/register_unfreeze_route.ts | 0 .../server/routes/api/mapping/index.ts | 0 .../api/mapping/register_mapping_route.ts | 0 .../server/routes/api/settings/index.ts | 0 .../api/settings/register_load_route.ts | 0 .../api/settings/register_settings_routes.ts | 0 .../api/settings/register_update_route.ts | 0 .../server/routes/api/stats/index.ts | 0 .../routes/api/stats/register_stats_route.ts | 0 .../server/routes/api/templates/index.ts | 0 .../api/templates/register_create_route.ts | 0 .../api/templates/register_delete_route.ts | 0 .../api/templates/register_get_routes.ts | 0 .../api/templates/register_template_routes.ts | 0 .../api/templates/register_update_route.ts | 0 .../routes/api/templates/validate_schemas.ts | 0 .../index_management/server/routes/helpers.ts | 0 .../index_management/server/routes/index.ts | 0 .../index_management/server/services/index.ts | 0 .../server/services/index_data_enricher.ts | 0 .../server/services/license.ts | 5 +- .../plugins/index_management/server/types.ts | 2 +- .../index_management/test/fixtures/index.ts | 0 .../test/fixtures/template.ts | 2 +- 365 files changed, 297 insertions(+), 261 deletions(-) delete mode 100644 x-pack/legacy/plugins/index_management/public/index.html rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/helpers/constants.ts (100%) rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts (96%) rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts (100%) rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/helpers/index.ts (95%) rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx (95%) rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts (85%) rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts (84%) rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts (85%) rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts (99%) rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/home.test.ts (100%) rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/template_clone.test.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/template_create.test.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/__jest__/client_integration/template_edit.test.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/__jest__/components/__snapshots__/index_table.test.js.snap (100%) rename x-pack/{legacy => }/plugins/index_management/__jest__/components/index_table.test.js (98%) rename x-pack/{legacy => }/plugins/index_management/__jest__/lib/__snapshots__/flatten_object.test.js.snap (100%) rename x-pack/{legacy => }/plugins/index_management/__jest__/lib/flatten_object.test.js (100%) rename x-pack/{legacy => }/plugins/index_management/__mocks__/ace.js (100%) rename x-pack/{legacy => }/plugins/index_management/__mocks__/ui/documentation_links.js (100%) rename x-pack/{legacy => }/plugins/index_management/__mocks__/ui/notify.js (100%) rename x-pack/{legacy => }/plugins/index_management/common/constants/api_base_path.ts (100%) rename x-pack/{legacy => }/plugins/index_management/common/constants/base_path.ts (100%) rename x-pack/{legacy => }/plugins/index_management/common/constants/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/common/constants/index_statuses.ts (100%) rename x-pack/{legacy => }/plugins/index_management/common/constants/invalid_characters.ts (100%) rename x-pack/{legacy => }/plugins/index_management/common/constants/plugin.ts (86%) rename x-pack/{legacy => }/plugins/index_management/common/constants/ui_metric.ts (100%) rename x-pack/{legacy => }/plugins/index_management/common/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/common/lib/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/common/lib/template_serialization.ts (100%) rename x-pack/{legacy => }/plugins/index_management/common/types/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/common/types/templates.ts (100%) create mode 100644 x-pack/plugins/index_management/kibana.json rename x-pack/{legacy => }/plugins/index_management/public/application/app.tsx (98%) rename x-pack/{legacy => }/plugins/index_management/public/application/app_context.tsx (90%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/index.ts (90%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/mappings_editor.helpers.ts (85%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/_index.scss (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/_index.scss (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/code_block.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form.tsx (98%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form_schema.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/dynamic_mapping_section/dynamic_mapping_section.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/dynamic_mapping_section/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/meta_field_section/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/meta_field_section/meta_field_section.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/routing_section.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/source_field_section.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/_index.scss (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/document_fields.tsx (91%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/document_fields_header.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzer_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzer_parameter_selects.tsx (86%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzers_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/boost_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/coerce_number_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/coerce_shape_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/copy_to_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/doc_values_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/dynamic_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/eager_global_ordinals_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/enabled_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_frequency_filter_absolute.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_frequency_filter_percentage.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/format_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/ignore_malformed.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/ignore_z_value_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/locale_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/max_shingle_size_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/name_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/norms_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/null_value_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/orientation_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/path_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/relations_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/similarity_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/split_queries_on_whitespace_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/store_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/term_vector_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/type_parameter.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/_field_list_item.scss (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/_index.scss (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx (83%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/alias_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/dense_vector_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/scaled_float_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/token_count_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/delete_field_provider.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/_edit_field_form_row.scss (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/_index.scss (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/advanced_parameters_section.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/basic_parameters_section.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_container.tsx (97%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_form_row.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_header_form.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/field_description_section.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/update_field_provider.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/alias_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/binary_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/boolean_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/completion_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/date_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/dense_vector_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/flattened_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/geo_point_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/geo_shape_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/ip_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/join_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/keyword_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/nested_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/numeric_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/object_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/range_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/search_as_you_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/shape_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/text_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/token_count_type.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item_container.tsx (92%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/modal_confirmation_delete_fields.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields_json_editor.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields_tree_editor.tsx (88%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/fields_tree.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_from_json_button.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.test.tsx (98%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/multiple_mappings_warning.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/templates_form/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/templates_form/templates_form.tsx (98%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/templates_form/templates_form_schema.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/tree/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/tree/tree.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/components/tree/tree_item.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/constants/default_values.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/constants/field_options.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/constants/field_options_i18n.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/constants/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/constants/mappings_editor.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/constants/parameters_definition.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/index_settings_context.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/lib/error_reporter.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/lib/extract_mappings_definition.test.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/lib/extract_mappings_definition.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/lib/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/lib/mappings_validator.test.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/lib/mappings_validator.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.test.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/lib/serializers.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/lib/validators.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/mappings_editor.tsx (98%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/mappings_state.tsx (98%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/reducer.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/shared_imports.ts (72%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/mappings_editor/types.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/no_match/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/no_match/no_match.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/page_error/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/page_error/page_error_forbidden.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/section_error.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/section_loading.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_delete_modal.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_form/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_form/steps/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_form/steps/step_aliases.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_form/steps/step_logistics.tsx (94%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_form/steps/step_mappings.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_form/steps/step_review.tsx (98%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_form/steps/step_settings.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_form/steps/use_json_step.ts (83%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_form/template_form.tsx (92%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_form/template_form_schemas.tsx (96%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_form/template_steps.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/components/template_form/types.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/constants/detail_panel_tabs.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/constants/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/constants/refresh_intervals.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/index.tsx (94%) rename x-pack/{legacy => }/plugins/index_management/public/application/lib/ace.js (94%) rename x-pack/{legacy => }/plugins/index_management/public/application/lib/edit_settings.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/lib/flatten_object.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/lib/flatten_panel_tree.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/lib/index_status_labels.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/lib/manage_angular_lifecycle.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/lib/render_badges.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/home.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/detail_panel/detail_panel.container.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/detail_panel/detail_panel.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/edit_settings_json.container.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/edit_settings_json.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/index.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/detail_panel/index.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/index.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/show_json.container.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/show_json.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/index.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/summary.container.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/summary.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.container.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/index_list.d.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/index_list.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/index_table/index.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.container.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/template_list/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/template_list/template_details/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_aliases.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_mappings.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_settings.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/template_list/template_details/template_details.tsx (98%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/template_list/template_list.tsx (97%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/template_list/template_table/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/home/template_list/template_table/template_table.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/template_clone/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/template_clone/template_clone.tsx (96%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/template_create/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/template_create/template_create.tsx (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/template_edit/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/sections/template_edit/template_edit.tsx (96%) rename x-pack/{legacy => }/plugins/index_management/public/application/services/api.ts (98%) rename x-pack/{legacy => }/plugins/index_management/public/application/services/breadcrumbs.ts (96%) rename x-pack/{legacy => }/plugins/index_management/public/application/services/documentation.ts (98%) rename x-pack/{legacy => }/plugins/index_management/public/application/services/health_to_color.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/services/http.ts (88%) rename x-pack/{legacy => }/plugins/index_management/public/application/services/index.ts (96%) rename x-pack/{legacy => }/plugins/index_management/public/application/services/navigation.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/services/notification.ts (93%) rename x-pack/{legacy => }/plugins/index_management/public/application/services/routing.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/services/sort_table.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/services/ui_metric.ts (90%) rename x-pack/{legacy => }/plugins/index_management/public/application/services/use_request.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/clear_cache_indices.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/clear_row_status.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/close_indices.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/delete_indices.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/detail_panel.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/edit_index_settings.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/extension_action.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/flush_indices.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/forcemerge_indices.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/freeze_indices.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/index.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/load_index_data.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/load_indices.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/open_indices.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/refresh_indices.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/reload_indices.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/table_state.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/unfreeze_indices.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/actions/update_index_settings.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/reducers/detail_panel.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/reducers/index.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/reducers/index_management.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/reducers/indices.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/reducers/row_status.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/reducers/table_state.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/selectors/index.d.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/selectors/index.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/store.d.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/application/store/store.js (100%) rename x-pack/{legacy => }/plugins/index_management/public/index.scss (100%) rename x-pack/{legacy => }/plugins/index_management/public/index.ts (66%) rename x-pack/{legacy => }/plugins/index_management/public/mocks.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/plugin.ts (90%) rename x-pack/{legacy => }/plugins/index_management/public/services/extensions_service.mock.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/services/extensions_service.ts (100%) rename x-pack/{legacy => }/plugins/index_management/public/services/index.ts (100%) create mode 100644 x-pack/plugins/index_management/public/shared_imports.ts rename x-pack/{legacy => }/plugins/index_management/public/types.ts (100%) rename x-pack/{legacy/plugins/index_management/public/shared_imports.ts => plugins/index_management/server/config.ts} (52%) rename x-pack/{legacy => }/plugins/index_management/server/index.ts (67%) rename x-pack/{legacy => }/plugins/index_management/server/lib/fetch_aliases.test.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/lib/fetch_aliases.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/lib/fetch_indices.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/lib/get_managed_templates.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/lib/is_es_error.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/plugin.ts (94%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/register_close_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/register_delete_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/register_flush_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/register_freeze_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/register_indices_routes.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/register_list_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/register_open_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/register_refresh_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/register_reload_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/indices/register_unfreeze_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/mapping/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/mapping/register_mapping_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/settings/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/settings/register_load_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/settings/register_settings_routes.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/settings/register_update_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/stats/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/stats/register_stats_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/templates/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/templates/register_create_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/templates/register_delete_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/templates/register_get_routes.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/templates/register_template_routes.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/templates/register_update_route.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/api/templates/validate_schemas.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/helpers.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/routes/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/services/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/services/index_data_enricher.ts (100%) rename x-pack/{legacy => }/plugins/index_management/server/services/license.ts (89%) rename x-pack/{legacy => }/plugins/index_management/server/types.ts (92%) rename x-pack/{legacy => }/plugins/index_management/test/fixtures/index.ts (100%) rename x-pack/{legacy => }/plugins/index_management/test/fixtures/template.ts (88%) diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index f22f7e98d3b8a..b1cb9075434e8 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -16,7 +16,7 @@ "xpack.fileUpload": "legacy/plugins/file_upload", "xpack.graph": ["legacy/plugins/graph", "plugins/graph"], "xpack.grokDebugger": "legacy/plugins/grokdebugger", - "xpack.idxMgmt": "legacy/plugins/index_management", + "xpack.idxMgmt": "plugins/index_management", "xpack.indexLifecycleMgmt": "legacy/plugins/index_lifecycle_management", "xpack.infra": "plugins/infra", "xpack.ingestManager": "plugins/ingest_manager", diff --git a/x-pack/legacy/plugins/cross_cluster_replication/index.js b/x-pack/legacy/plugins/cross_cluster_replication/index.js index 1b5f42fc5107e..1b3aafcad5c0f 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/index.js +++ b/x-pack/legacy/plugins/cross_cluster_replication/index.js @@ -49,13 +49,12 @@ export function crossClusterReplication(kibana) { init: function initCcrPlugin(server) { registerLicenseChecker(server); registerRoutes(server); - if ( server.config().get('xpack.ccr.ui.enabled') && - server.plugins.index_management && - server.plugins.index_management.addIndexManagementDataEnricher + server.newPlatform.setup.plugins.indexManagement && + server.newPlatform.setup.plugins.indexManagement.indexDataEnricher ) { - server.plugins.index_management.addIndexManagementDataEnricher(ccrDataEnricher); + server.newPlatform.setup.plugins.indexManagement.indexDataEnricher.add(ccrDataEnricher); } }, }); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js b/x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js index 16ed0a7d695ad..7b31ffa5024b7 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js +++ b/x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js @@ -7,7 +7,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage } from '@kbn/i18n/react'; -import { getIndexListUri } from '../../../../../../../../index_management/public/application/services/navigation'; +import { getIndexListUri } from '../../../../../../../../../../plugins/index_management/public'; import { EuiButtonEmpty, diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.js b/x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.js index e3bda2e67097d..2ad118d28f38d 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.js +++ b/x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.js @@ -7,8 +7,6 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage } from '@kbn/i18n/react'; -import { getIndexListUri } from '../../../../../../../../index_management/public/application/services/navigation'; - import { EuiButton, EuiButtonEmpty, @@ -31,12 +29,11 @@ import { EuiTextColor, EuiTitle, } from '@elastic/eui'; - import 'brace/theme/textmate'; -import { ContextMenu } from '../context_menu'; - +import { getIndexListUri } from '../../../../../../../../../../plugins/index_management/public'; import { API_STATUS } from '../../../../../constants'; +import { ContextMenu } from '../context_menu'; export class DetailPanel extends Component { static propTypes = { diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/extend_index_management/index.js b/x-pack/legacy/plugins/cross_cluster_replication/public/extend_index_management/index.js index 809a7c3e87b75..c44918c500849 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/extend_index_management/index.js +++ b/x-pack/legacy/plugins/cross_cluster_replication/public/extend_index_management/index.js @@ -4,11 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ import { i18n } from '@kbn/i18n'; -import { extensionsService } from '../../../index_management/public'; +import { npSetup } from 'ui/new_platform'; import { get } from 'lodash'; const propertyPath = 'isFollowerIndex'; -export const followerBadgeExtension = { + +const followerBadgeExtension = { matchIndex: index => { return get(index, propertyPath); }, @@ -19,4 +20,6 @@ export const followerBadgeExtension = { filterExpression: 'isFollowerIndex:true', }; -extensionsService.addBadge(followerBadgeExtension); +if (npSetup.plugins.indexManagement) { + npSetup.plugins.indexManagement.extensionsService.addBadge(followerBadgeExtension); +} diff --git a/x-pack/legacy/plugins/index_lifecycle_management/__jest__/extend_index_management.test.js b/x-pack/legacy/plugins/index_lifecycle_management/__jest__/extend_index_management.test.js index bcbae7e093f46..d2619778617c3 100644 --- a/x-pack/legacy/plugins/index_lifecycle_management/__jest__/extend_index_management.test.js +++ b/x-pack/legacy/plugins/index_lifecycle_management/__jest__/extend_index_management.test.js @@ -27,8 +27,10 @@ initHttp(axios.create({ adapter: axiosXhrAdapter }), path => path); initUiMetric(() => () => {}); jest.mock('ui/new_platform'); -jest.mock('../../index_management/public', async () => { - const { indexManagementMock } = await import('../../index_management/public/mocks.ts'); +jest.mock('../../../../plugins/index_management/public', async () => { + const { indexManagementMock } = await import( + '../../../../plugins/index_management/public/mocks.ts' + ); return indexManagementMock.createSetup(); }); diff --git a/x-pack/legacy/plugins/index_lifecycle_management/plugin.ts b/x-pack/legacy/plugins/index_lifecycle_management/plugin.ts index 8d7f937039203..38d1bea45ce07 100644 --- a/x-pack/legacy/plugins/index_lifecycle_management/plugin.ts +++ b/x-pack/legacy/plugins/index_lifecycle_management/plugin.ts @@ -41,14 +41,14 @@ export class Plugin { registerPoliciesRoutes(server); registerTemplatesRoutes(server); - const serverPlugins = server.plugins as any; + const serverPlugins = server.newPlatform.setup.plugins as any; if ( server.config().get('xpack.ilm.ui.enabled') && - serverPlugins.index_management && - serverPlugins.index_management.addIndexManagementDataEnricher + serverPlugins.indexManagement && + serverPlugins.indexManagement.indexDataEnricher ) { - serverPlugins.index_management.addIndexManagementDataEnricher(indexLifecycleDataEnricher); + serverPlugins.indexManagement.indexDataEnricher.add(indexLifecycleDataEnricher); } } } diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/legacy.ts b/x-pack/legacy/plugins/index_lifecycle_management/public/legacy.ts index 3c21a644c0f78..f7f924add2c51 100644 --- a/x-pack/legacy/plugins/index_lifecycle_management/public/legacy.ts +++ b/x-pack/legacy/plugins/index_lifecycle_management/public/legacy.ts @@ -20,7 +20,9 @@ import { addAllExtensions } from './np_ready/extend_index_management'; if (chrome.getInjected('ilmUiEnabled')) { // We have to initialize this outside of the NP lifecycle, otherwise these extensions won't // be available in Index Management unless the user visits ILM first. - addAllExtensions(); + if ((npSetup.plugins as any).indexManagement) { + addAllExtensions((npSetup.plugins as any).indexManagement.extensionsService); + } // This method handles the cleanup needed when route is scope is destroyed. It also prevents Angular // from destroying scope when route changes and both old route and new route are this same route. diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/policy_table.js b/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/policy_table.js index 83d32eae1097d..903161fe094fc 100644 --- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/policy_table.js +++ b/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/application/sections/policy_table/components/policy_table/policy_table.js @@ -37,7 +37,7 @@ import { import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services'; -import { getIndexListUri } from '../../../../../../../../index_management/public/application/services/navigation'; +import { getIndexListUri } from '../../../../../../../../../../plugins/index_management/public'; import { BASE_PATH } from '../../../../../../../common/constants'; import { UIM_EDIT_CLICK } from '../../../../constants'; import { getPolicyPath } from '../../../../services/navigation'; diff --git a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/index.js b/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/index.js index 0e662b78b2c18..69658d31695bc 100644 --- a/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/index.js +++ b/x-pack/legacy/plugins/index_lifecycle_management/public/np_ready/extend_index_management/index.js @@ -9,7 +9,6 @@ import { get, every, any } from 'lodash'; import { i18n } from '@kbn/i18n'; import { EuiSearchBar } from '@elastic/eui'; -import { extensionsService } from '../../../../index_management/public'; import { init as initUiMetric } from '../application/services/ui_metric'; import { init as initNotification } from '../application/services/notification'; import { retryLifecycleForIndex } from '../application/services/api'; @@ -238,7 +237,7 @@ export const ilmFilterExtension = indices => { } }; -export const addAllExtensions = () => { +export const addAllExtensions = extensionsService => { extensionsService.addAction(retryLifecycleActionExtension); extensionsService.addAction(removeLifecyclePolicyActionExtension); extensionsService.addAction(addLifecyclePolicyActionExtension); diff --git a/x-pack/legacy/plugins/index_management/index.ts b/x-pack/legacy/plugins/index_management/index.ts index c92b38c0d94be..9eba98a526d2b 100644 --- a/x-pack/legacy/plugins/index_management/index.ts +++ b/x-pack/legacy/plugins/index_management/index.ts @@ -4,36 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { resolve } from 'path'; -import { Legacy } from 'kibana'; -import { PLUGIN } from './common/constants'; -import { plugin as initServerPlugin, Dependencies } from './server'; - -export type ServerFacade = Legacy.Server; - export function indexManagement(kibana: any) { return new kibana.Plugin({ - id: PLUGIN.id, + id: 'index_management', configPrefix: 'xpack.index_management', - publicDir: resolve(__dirname, 'public'), - require: ['kibana', 'elasticsearch', 'xpack_main'], - - uiExports: { - styleSheetPaths: resolve(__dirname, 'public/index.scss'), - managementSections: ['plugins/index_management'], - }, - - init(server: ServerFacade) { - const coreSetup = server.newPlatform.setup.core; - const coreInitializerContext = server.newPlatform.coreContext; - const pluginsSetup: Dependencies = { - licensing: server.newPlatform.setup.plugins.licensing as any, - }; - - const serverPlugin = initServerPlugin(coreInitializerContext as any); - const serverPublicApi = serverPlugin.setup(coreSetup, pluginsSetup); - - server.expose('addIndexManagementDataEnricher', serverPublicApi.indexDataEnricher.add); - }, }); } diff --git a/x-pack/legacy/plugins/index_management/public/index.html b/x-pack/legacy/plugins/index_management/public/index.html deleted file mode 100644 index 0e9ac6fa0bc97..0000000000000 --- a/x-pack/legacy/plugins/index_management/public/index.html +++ /dev/null @@ -1,3 +0,0 @@ - -
-
diff --git a/x-pack/legacy/plugins/remote_clusters/index.ts b/x-pack/legacy/plugins/remote_clusters/index.ts index 37b2224f8d7c2..439cb818d8a56 100644 --- a/x-pack/legacy/plugins/remote_clusters/index.ts +++ b/x-pack/legacy/plugins/remote_clusters/index.ts @@ -5,6 +5,8 @@ */ import { resolve } from 'path'; +import { Legacy } from 'kibana'; + import { PLUGIN } from './common'; export function remoteClusters(kibana: any) { @@ -28,7 +30,7 @@ export function remoteClusters(kibana: any) { enabled: Joi.boolean().default(true), }).default(); }, - isEnabled(config: any) { + isEnabled(config: Legacy.KibanaConfig) { return ( config.get('xpack.remote_clusters.enabled') && config.get('xpack.index_management.enabled') ); diff --git a/x-pack/legacy/plugins/rollup/index.ts b/x-pack/legacy/plugins/rollup/index.ts index 7548af23b3aae..2c8363cc397f4 100644 --- a/x-pack/legacy/plugins/rollup/index.ts +++ b/x-pack/legacy/plugins/rollup/index.ts @@ -40,7 +40,7 @@ export function rollup(kibana: any) { }, init(server: any) { const { core: coreSetup, plugins } = server.newPlatform.setup; - const { usageCollection, metrics } = plugins; + const { usageCollection, metrics, indexManagement } = plugins; const rollupSetup = (plugins.rollup as unknown) as RollupSetup; @@ -54,11 +54,11 @@ export function rollup(kibana: any) { rollupPluginInstance.setup(coreSetup, { usageCollection, metrics, + indexManagement, __LEGACY: { plugins: { xpack_main: server.plugins.xpack_main, rollup: server.plugins[PLUGIN.ID], - index_management: server.plugins.index_management, }, }, }); diff --git a/x-pack/legacy/plugins/rollup/public/legacy.ts b/x-pack/legacy/plugins/rollup/public/legacy.ts index 64eb1f6436389..e3e663ac7b0f4 100644 --- a/x-pack/legacy/plugins/rollup/public/legacy.ts +++ b/x-pack/legacy/plugins/rollup/public/legacy.ts @@ -10,7 +10,6 @@ import { aggTypeFieldFilters } from 'ui/agg_types'; import { addSearchStrategy } from '../../../../../src/plugins/data/public'; import { RollupPlugin } from './plugin'; import { setup as management } from '../../../../../src/legacy/core_plugins/management/public/legacy'; -import { extensionsService } from '../../index_management/public'; const plugin = new RollupPlugin(); @@ -20,7 +19,6 @@ export const setup = plugin.setup(npSetup.core, { aggTypeFilters, aggTypeFieldFilters, addSearchStrategy, - indexManagementExtensions: extensionsService, managementLegacy: management, }, }); diff --git a/x-pack/legacy/plugins/rollup/public/plugin.ts b/x-pack/legacy/plugins/rollup/public/plugin.ts index 90d7e2d9d0191..a01383f4733ef 100644 --- a/x-pack/legacy/plugins/rollup/public/plugin.ts +++ b/x-pack/legacy/plugins/rollup/public/plugin.ts @@ -27,7 +27,7 @@ import { // @ts-ignore import { CRUD_APP_BASE_PATH } from './crud_app/constants'; import { ManagementSetup } from '../../../../../src/plugins/management/public'; -import { IndexMgmtSetup } from '../../index_management/public'; +import { IndexMgmtSetup } from '../../../../plugins/index_management/public'; // @ts-ignore import { setEsBaseAndXPackBase, setHttp } from './crud_app/services'; import { setNotifications, setFatalErrors } from './kibana_services'; @@ -39,30 +39,28 @@ export interface RollupPluginSetupDependencies { aggTypeFieldFilters: AggTypeFieldFilters; addSearchStrategy: (searchStrategy: SearchStrategyProvider) => void; managementLegacy: ManagementSetupLegacy; - indexManagementExtensions: IndexMgmtSetup['extensionsService']; }; home?: HomePublicPluginSetup; management: ManagementSetup; + indexManagement?: IndexMgmtSetup; } export class RollupPlugin implements Plugin { setup( core: CoreSetup, { - __LEGACY: { - aggTypeFilters, - aggTypeFieldFilters, - addSearchStrategy, - managementLegacy, - indexManagementExtensions, - }, + __LEGACY: { aggTypeFilters, aggTypeFieldFilters, addSearchStrategy, managementLegacy }, home, management, + indexManagement, }: RollupPluginSetupDependencies ) { setFatalErrors(core.fatalErrors); - indexManagementExtensions.addBadge(rollupBadgeExtension); - indexManagementExtensions.addToggle(rollupToggleExtension); + + if (indexManagement) { + indexManagement.extensionsService.addBadge(rollupBadgeExtension); + indexManagement.extensionsService.addToggle(rollupToggleExtension); + } const isRollupIndexPatternsEnabled = core.uiSettings.get(CONFIG_ROLLUPS); diff --git a/x-pack/legacy/plugins/rollup/server/plugin.ts b/x-pack/legacy/plugins/rollup/server/plugin.ts index 52b1e31af4eb2..090cb8a47377a 100644 --- a/x-pack/legacy/plugins/rollup/server/plugin.ts +++ b/x-pack/legacy/plugins/rollup/server/plugin.ts @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { VisTypeTimeseriesSetup } from 'src/plugins/vis_type_timeseries/server'; +import { IndexMgmtSetup } from '../../../../plugins/index_management/server'; import { registerLicenseChecker } from '../../../server/lib/register_license_checker'; import { PLUGIN } from '../common'; import { ServerShim, RouteDependencies } from './types'; @@ -38,10 +39,12 @@ export class RollupsServerPlugin implements Plugin { __LEGACY: serverShim, usageCollection, metrics, + indexManagement, }: { __LEGACY: ServerShim; usageCollection?: UsageCollectionSetup; metrics?: VisTypeTimeseriesSetup; + indexManagement?: IndexMgmtSetup; } ) { const elasticsearch = await elasticsearchService.adminClient; @@ -76,11 +79,8 @@ export class RollupsServerPlugin implements Plugin { }); } - if ( - serverShim.plugins.index_management && - serverShim.plugins.index_management.addIndexManagementDataEnricher - ) { - serverShim.plugins.index_management.addIndexManagementDataEnricher(rollupDataEnricher); + if (indexManagement && indexManagement.indexDataEnricher) { + indexManagement.indexDataEnricher.add(rollupDataEnricher); } if (metrics) { diff --git a/x-pack/legacy/plugins/rollup/server/rollup_data_enricher.ts b/x-pack/legacy/plugins/rollup/server/rollup_data_enricher.ts index 7c5e160c54a31..ad621f2d9ba80 100644 --- a/x-pack/legacy/plugins/rollup/server/rollup_data_enricher.ts +++ b/x-pack/legacy/plugins/rollup/server/rollup_data_enricher.ts @@ -4,14 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -interface Index { - name: string; - [key: string]: unknown; -} +import { Index } from '../../../../plugins/index_management/server'; export const rollupDataEnricher = async (indicesList: Index[], callWithRequest: any) => { if (!indicesList || !indicesList.length) { - return indicesList; + return Promise.resolve(indicesList); } const params = { diff --git a/x-pack/legacy/plugins/rollup/server/types.ts b/x-pack/legacy/plugins/rollup/server/types.ts index 62a4841133cff..bcc6770e9b8ee 100644 --- a/x-pack/legacy/plugins/rollup/server/types.ts +++ b/x-pack/legacy/plugins/rollup/server/types.ts @@ -11,7 +11,6 @@ export interface ServerShim { plugins: { xpack_main: XPackMainPlugin; rollup: any; - index_management: any; }; } diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/constants.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/constants.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/constants.ts rename to x-pack/plugins/index_management/__jest__/client_integration/helpers/constants.ts diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts similarity index 96% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts rename to x-pack/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts index e5f0b25d89c3e..7e3e1fba9c44a 100644 --- a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts @@ -12,10 +12,10 @@ import { TestBedConfig, findTestSubject, nextTick, -} from '../../../../../../test_utils'; -import { IndexManagementHome } from '../../../public/application/sections/home'; +} from '../../../../../test_utils'; +import { IndexManagementHome } from '../../../public/application/sections/home'; // eslint-disable-line @kbn/eslint/no-restricted-paths import { BASE_PATH } from '../../../common/constants'; -import { indexManagementStore } from '../../../public/application/store'; +import { indexManagementStore } from '../../../public/application/store'; // eslint-disable-line @kbn/eslint/no-restricted-paths import { Template } from '../../../common/types'; import { WithAppDependencies, services } from './setup_environment'; diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts rename to x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/index.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/index.ts similarity index 95% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/index.ts rename to x-pack/plugins/index_management/__jest__/client_integration/helpers/index.ts index 6dce4453a67f9..66021b531919a 100644 --- a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/index.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/index.ts @@ -9,7 +9,7 @@ import { setup as templateCreateSetup } from './template_create.helpers'; import { setup as templateCloneSetup } from './template_clone.helpers'; import { setup as templateEditSetup } from './template_edit.helpers'; -export { nextTick, getRandomString, findTestSubject, TestBed } from '../../../../../../test_utils'; +export { nextTick, getRandomString, findTestSubject, TestBed } from '../../../../../test_utils'; export { setupEnvironment } from './setup_environment'; diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx b/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx similarity index 95% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx rename to x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx index 0212efe1f322d..1eaf7efd17395 100644 --- a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +/* eslint-disable @kbn/eslint/no-restricted-paths */ import React from 'react'; import axios from 'axios'; import axiosXhrAdapter from 'axios/lib/adapters/xhr'; @@ -10,7 +11,7 @@ import axiosXhrAdapter from 'axios/lib/adapters/xhr'; import { notificationServiceMock, docLinksServiceMock, -} from '../../../../../../../src/core/public/mocks'; +} from '../../../../../../src/core/public/mocks'; import { AppContextProvider } from '../../../public/application/app_context'; import { httpService } from '../../../public/application/services/http'; import { breadcrumbService } from '../../../public/application/services/breadcrumbs'; diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts similarity index 85% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts rename to x-pack/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts index cd1b67c08d934..36498b99ba143 100644 --- a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { registerTestBed, TestBedConfig } from '../../../../../../test_utils'; +import { registerTestBed, TestBedConfig } from '../../../../../test_utils'; import { BASE_PATH } from '../../../common/constants'; -import { TemplateClone } from '../../../public/application/sections/template_clone'; +import { TemplateClone } from '../../../public/application/sections/template_clone'; // eslint-disable-line @kbn/eslint/no-restricted-paths import { formSetup } from './template_form.helpers'; import { TEMPLATE_NAME } from './constants'; import { WithAppDependencies } from './setup_environment'; diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts similarity index 84% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts rename to x-pack/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts index 8e62bc25d6bd1..14a44968a93c3 100644 --- a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { registerTestBed, TestBedConfig } from '../../../../../../test_utils'; +import { registerTestBed, TestBedConfig } from '../../../../../test_utils'; import { BASE_PATH } from '../../../common/constants'; -import { TemplateCreate } from '../../../public/application/sections/template_create'; +import { TemplateCreate } from '../../../public/application/sections/template_create'; // eslint-disable-line @kbn/eslint/no-restricted-paths import { formSetup, TestSubjects } from './template_form.helpers'; import { WithAppDependencies } from './setup_environment'; diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts similarity index 85% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts rename to x-pack/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts index cb1025234b48e..af5fa8b79ecad 100644 --- a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { registerTestBed, TestBedConfig } from '../../../../../../test_utils'; +import { registerTestBed, TestBedConfig } from '../../../../../test_utils'; import { BASE_PATH } from '../../../common/constants'; -import { TemplateEdit } from '../../../public/application/sections/template_edit'; +import { TemplateEdit } from '../../../public/application/sections/template_edit'; // eslint-disable-line @kbn/eslint/no-restricted-paths import { formSetup, TestSubjects } from './template_form.helpers'; import { TEMPLATE_NAME } from './constants'; import { WithAppDependencies } from './setup_environment'; diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts similarity index 99% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts rename to x-pack/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts index a7c87723b33fb..134c67c278b22 100644 --- a/x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { TestBed, SetupFunc, UnwrapPromise } from '../../../../../../test_utils'; +import { TestBed, SetupFunc, UnwrapPromise } from '../../../../../test_utils'; import { Template } from '../../../common/types'; import { nextTick } from './index'; diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/home.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home.test.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/home.test.ts rename to x-pack/plugins/index_management/__jest__/client_integration/home.test.ts diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/template_clone.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/template_clone.test.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/template_clone.test.tsx rename to x-pack/plugins/index_management/__jest__/client_integration/template_clone.test.tsx diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/template_create.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/template_create.test.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/template_create.test.tsx rename to x-pack/plugins/index_management/__jest__/client_integration/template_create.test.tsx diff --git a/x-pack/legacy/plugins/index_management/__jest__/client_integration/template_edit.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/template_edit.test.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/__jest__/client_integration/template_edit.test.tsx rename to x-pack/plugins/index_management/__jest__/client_integration/template_edit.test.tsx diff --git a/x-pack/legacy/plugins/index_management/__jest__/components/__snapshots__/index_table.test.js.snap b/x-pack/plugins/index_management/__jest__/components/__snapshots__/index_table.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/index_management/__jest__/components/__snapshots__/index_table.test.js.snap rename to x-pack/plugins/index_management/__jest__/components/__snapshots__/index_table.test.js.snap diff --git a/x-pack/legacy/plugins/index_management/__jest__/components/index_table.test.js b/x-pack/plugins/index_management/__jest__/components/index_table.test.js similarity index 98% rename from x-pack/legacy/plugins/index_management/__jest__/components/index_table.test.js rename to x-pack/plugins/index_management/__jest__/components/index_table.test.js index 2b4fd89436458..15c3ef0b84562 100644 --- a/x-pack/legacy/plugins/index_management/__jest__/components/index_table.test.js +++ b/x-pack/plugins/index_management/__jest__/components/index_table.test.js @@ -20,13 +20,13 @@ import { setUiMetricService } from '../../public/application/services/api'; import { indexManagementStore } from '../../public/application/store'; import { setExtensionsService } from '../../public/application/store/selectors'; import { BASE_PATH, API_BASE_PATH } from '../../common/constants'; -import { mountWithIntl } from '../../../../../test_utils/enzyme_helpers'; +import { mountWithIntl } from '../../../../test_utils/enzyme_helpers'; import { ExtensionsService } from '../../public/services'; import sinon from 'sinon'; import { findTestSubject } from '@elastic/eui/lib/test'; /* eslint-disable @kbn/eslint/no-restricted-paths */ -import { notificationServiceMock } from '../../../../../../src/core/public/notifications/notifications_service.mock'; +import { notificationServiceMock } from '../../../../../src/core/public/notifications/notifications_service.mock'; jest.mock('ui/new_platform'); diff --git a/x-pack/legacy/plugins/index_management/__jest__/lib/__snapshots__/flatten_object.test.js.snap b/x-pack/plugins/index_management/__jest__/lib/__snapshots__/flatten_object.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/index_management/__jest__/lib/__snapshots__/flatten_object.test.js.snap rename to x-pack/plugins/index_management/__jest__/lib/__snapshots__/flatten_object.test.js.snap diff --git a/x-pack/legacy/plugins/index_management/__jest__/lib/flatten_object.test.js b/x-pack/plugins/index_management/__jest__/lib/flatten_object.test.js similarity index 100% rename from x-pack/legacy/plugins/index_management/__jest__/lib/flatten_object.test.js rename to x-pack/plugins/index_management/__jest__/lib/flatten_object.test.js diff --git a/x-pack/legacy/plugins/index_management/__mocks__/ace.js b/x-pack/plugins/index_management/__mocks__/ace.js similarity index 100% rename from x-pack/legacy/plugins/index_management/__mocks__/ace.js rename to x-pack/plugins/index_management/__mocks__/ace.js diff --git a/x-pack/legacy/plugins/index_management/__mocks__/ui/documentation_links.js b/x-pack/plugins/index_management/__mocks__/ui/documentation_links.js similarity index 100% rename from x-pack/legacy/plugins/index_management/__mocks__/ui/documentation_links.js rename to x-pack/plugins/index_management/__mocks__/ui/documentation_links.js diff --git a/x-pack/legacy/plugins/index_management/__mocks__/ui/notify.js b/x-pack/plugins/index_management/__mocks__/ui/notify.js similarity index 100% rename from x-pack/legacy/plugins/index_management/__mocks__/ui/notify.js rename to x-pack/plugins/index_management/__mocks__/ui/notify.js diff --git a/x-pack/legacy/plugins/index_management/common/constants/api_base_path.ts b/x-pack/plugins/index_management/common/constants/api_base_path.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/common/constants/api_base_path.ts rename to x-pack/plugins/index_management/common/constants/api_base_path.ts diff --git a/x-pack/legacy/plugins/index_management/common/constants/base_path.ts b/x-pack/plugins/index_management/common/constants/base_path.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/common/constants/base_path.ts rename to x-pack/plugins/index_management/common/constants/base_path.ts diff --git a/x-pack/legacy/plugins/index_management/common/constants/index.ts b/x-pack/plugins/index_management/common/constants/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/common/constants/index.ts rename to x-pack/plugins/index_management/common/constants/index.ts diff --git a/x-pack/legacy/plugins/index_management/common/constants/index_statuses.ts b/x-pack/plugins/index_management/common/constants/index_statuses.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/common/constants/index_statuses.ts rename to x-pack/plugins/index_management/common/constants/index_statuses.ts diff --git a/x-pack/legacy/plugins/index_management/common/constants/invalid_characters.ts b/x-pack/plugins/index_management/common/constants/invalid_characters.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/common/constants/invalid_characters.ts rename to x-pack/plugins/index_management/common/constants/invalid_characters.ts diff --git a/x-pack/legacy/plugins/index_management/common/constants/plugin.ts b/x-pack/plugins/index_management/common/constants/plugin.ts similarity index 86% rename from x-pack/legacy/plugins/index_management/common/constants/plugin.ts rename to x-pack/plugins/index_management/common/constants/plugin.ts index 2cd137f62d3db..e25f537edcf8d 100644 --- a/x-pack/legacy/plugins/index_management/common/constants/plugin.ts +++ b/x-pack/plugins/index_management/common/constants/plugin.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { LicenseType } from '../../../../../plugins/licensing/common/types'; +import { LicenseType } from '../../../licensing/common/types'; const basicLicense: LicenseType = 'basic'; diff --git a/x-pack/legacy/plugins/index_management/common/constants/ui_metric.ts b/x-pack/plugins/index_management/common/constants/ui_metric.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/common/constants/ui_metric.ts rename to x-pack/plugins/index_management/common/constants/ui_metric.ts diff --git a/x-pack/legacy/plugins/index_management/common/index.ts b/x-pack/plugins/index_management/common/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/common/index.ts rename to x-pack/plugins/index_management/common/index.ts diff --git a/x-pack/legacy/plugins/index_management/common/lib/index.ts b/x-pack/plugins/index_management/common/lib/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/common/lib/index.ts rename to x-pack/plugins/index_management/common/lib/index.ts diff --git a/x-pack/legacy/plugins/index_management/common/lib/template_serialization.ts b/x-pack/plugins/index_management/common/lib/template_serialization.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/common/lib/template_serialization.ts rename to x-pack/plugins/index_management/common/lib/template_serialization.ts diff --git a/x-pack/legacy/plugins/index_management/common/types/index.ts b/x-pack/plugins/index_management/common/types/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/common/types/index.ts rename to x-pack/plugins/index_management/common/types/index.ts diff --git a/x-pack/legacy/plugins/index_management/common/types/templates.ts b/x-pack/plugins/index_management/common/types/templates.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/common/types/templates.ts rename to x-pack/plugins/index_management/common/types/templates.ts diff --git a/x-pack/plugins/index_management/kibana.json b/x-pack/plugins/index_management/kibana.json new file mode 100644 index 0000000000000..7387a042988c0 --- /dev/null +++ b/x-pack/plugins/index_management/kibana.json @@ -0,0 +1,15 @@ +{ + "id": "indexManagement", + "version": "kibana", + "server": true, + "ui": true, + "requiredPlugins": [ + "home", + "licensing", + "management" + ], + "optionalPlugins": [ + "usageCollection" + ], + "configPath": ["xpack", "index_management"] +} diff --git a/x-pack/legacy/plugins/index_management/public/application/app.tsx b/x-pack/plugins/index_management/public/application/app.tsx similarity index 98% rename from x-pack/legacy/plugins/index_management/public/application/app.tsx rename to x-pack/plugins/index_management/public/application/app.tsx index 3b475f3baba04..83997dd6ece18 100644 --- a/x-pack/legacy/plugins/index_management/public/application/app.tsx +++ b/x-pack/plugins/index_management/public/application/app.tsx @@ -16,7 +16,7 @@ import { useServices } from './app_context'; export const App = () => { const { uiMetricService } = useServices(); - useEffect(() => uiMetricService.trackMetric('loaded', UIM_APP_LOAD), []); + useEffect(() => uiMetricService.trackMetric('loaded', UIM_APP_LOAD), [uiMetricService]); return ( diff --git a/x-pack/legacy/plugins/index_management/public/application/app_context.tsx b/x-pack/plugins/index_management/public/application/app_context.tsx similarity index 90% rename from x-pack/legacy/plugins/index_management/public/application/app_context.tsx rename to x-pack/plugins/index_management/public/application/app_context.tsx index 12e0d362a2930..2bb618ad8efce 100644 --- a/x-pack/legacy/plugins/index_management/public/application/app_context.tsx +++ b/x-pack/plugins/index_management/public/application/app_context.tsx @@ -5,9 +5,9 @@ */ import React, { createContext, useContext } from 'react'; -import { CoreStart } from '../../../../../../src/core/public'; +import { CoreStart } from '../../../../../src/core/public'; -import { UsageCollectionSetup } from '../../../../../../src/plugins/usage_collection/public'; +import { UsageCollectionSetup } from '../../../../../src/plugins/usage_collection/public'; import { IndexMgmtMetricsType } from '../types'; import { UiMetricService, NotificationService, HttpService } from './services'; import { ExtensionsService } from '../services'; diff --git a/x-pack/legacy/plugins/index_management/public/application/components/index.ts b/x-pack/plugins/index_management/public/application/components/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/index.ts rename to x-pack/plugins/index_management/public/application/components/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/index.ts similarity index 90% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/index.ts index e3313bfba56fd..6d64cb73da4bd 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/index.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/index.ts @@ -10,7 +10,7 @@ export { getRandomString, findTestSubject, TestBed, -} from '../../../../../../../../../../test_utils'; +} from '../../../../../../../../../test_utils'; export const componentHelpers = { mappingsEditor: { setup: mappingsEditorSetup }, diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/mappings_editor.helpers.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/mappings_editor.helpers.ts similarity index 85% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/mappings_editor.helpers.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/mappings_editor.helpers.ts index dcee956130a29..acb416654023e 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/mappings_editor.helpers.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/helpers/mappings_editor.helpers.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { registerTestBed } from '../../../../../../../../../../test_utils'; +import { registerTestBed } from '../../../../../../../../../test_utils'; import { MappingsEditor } from '../../../mappings_editor'; export const setup = (props: any) => diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/_index.scss b/x-pack/plugins/index_management/public/application/components/mappings_editor/_index.scss similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/_index.scss rename to x-pack/plugins/index_management/public/application/components/mappings_editor/_index.scss diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/_index.scss b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/_index.scss similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/_index.scss rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/_index.scss diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/code_block.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/code_block.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/code_block.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/code_block.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form.tsx similarity index 98% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form.tsx index 0c5c9e2a15b75..9b0b8420f9ea9 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form.tsx @@ -110,7 +110,7 @@ export const ConfigurationForm = React.memo(({ defaultValue }: Props) => { }); }); return subscription.unsubscribe; - }, [form]); + }, [form, dispatch]); useEffect(() => { if (didMountRef.current) { @@ -121,14 +121,14 @@ export const ConfigurationForm = React.memo(({ defaultValue }: Props) => { // Avoid reseting the form on component mount. didMountRef.current = true; } - }, [defaultValue]); + }, [defaultValue, form]); useEffect(() => { return () => { // On unmount => save in the state a snapshot of the current form data. dispatch({ type: 'configuration.save' }); }; - }, []); + }, [dispatch]); return ( diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form_schema.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form_schema.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form_schema.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form_schema.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/dynamic_mapping_section/dynamic_mapping_section.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/dynamic_mapping_section/dynamic_mapping_section.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/dynamic_mapping_section/dynamic_mapping_section.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/dynamic_mapping_section/dynamic_mapping_section.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/dynamic_mapping_section/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/dynamic_mapping_section/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/dynamic_mapping_section/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/dynamic_mapping_section/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/meta_field_section/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/meta_field_section/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/meta_field_section/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/meta_field_section/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/meta_field_section/meta_field_section.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/meta_field_section/meta_field_section.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/meta_field_section/meta_field_section.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/meta_field_section/meta_field_section.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/routing_section.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/routing_section.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/routing_section.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/routing_section.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/source_field_section.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/source_field_section.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/source_field_section.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/source_field_section.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/_index.scss b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/_index.scss similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/_index.scss rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/_index.scss diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/document_fields.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/document_fields.tsx similarity index 91% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/document_fields.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/document_fields.tsx index 378d669dee69c..400de4052afa4 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/document_fields.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/document_fields.tsx @@ -24,7 +24,7 @@ export const DocumentFields = React.memo(() => { if (editorType === 'json') { return deNormalize(fields); } - }, [editorType]); + }, [editorType, fields]); const editor = editorType === 'json' ? ( @@ -41,9 +41,12 @@ export const DocumentFields = React.memo(() => { return ; }; - const onSearchChange = useCallback((value: string) => { - dispatch({ type: 'search:update', value }); - }, []); + const onSearchChange = useCallback( + (value: string) => { + dispatch({ type: 'search:update', value }); + }, + [dispatch] + ); const searchTerm = search.term.trim(); diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/document_fields_header.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/document_fields_header.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/document_fields_header.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/document_fields_header.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/editor_toggle_controls.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzer_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzer_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzer_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzer_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzer_parameter_selects.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzer_parameter_selects.tsx similarity index 86% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzer_parameter_selects.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzer_parameter_selects.tsx index de3d70db31af4..a91231352c168 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzer_parameter_selects.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzer_parameter_selects.tsx @@ -56,15 +56,21 @@ export const AnalyzerParameterSelects = ({ }); return subscription.unsubscribe; - }, [form]); + }, [form, onChange]); - const getSubOptionsMeta = (mainValue: string) => - mapOptionsToSubOptions !== undefined ? mapOptionsToSubOptions[mainValue] : undefined; + const getSubOptionsMeta = useCallback( + (mainValue: string) => + mapOptionsToSubOptions !== undefined ? mapOptionsToSubOptions[mainValue] : undefined, + [mapOptionsToSubOptions] + ); - const onMainValueChange = useCallback((mainValue: unknown) => { - const subOptionsMeta = getSubOptionsMeta(mainValue as string); - form.setFieldValue('sub', subOptionsMeta ? subOptionsMeta.options[0].value : undefined); - }, []); + const onMainValueChange = useCallback( + (mainValue: unknown) => { + const subOptionsMeta = getSubOptionsMeta(mainValue as string); + form.setFieldValue('sub', subOptionsMeta ? subOptionsMeta.options[0].value : undefined); + }, + [form, getSubOptionsMeta] + ); const renderSelect = (field: FieldHook, opts: Options) => { const isSuperSelect = areOptionsSuperSelect(opts); diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzers_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzers_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzers_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/analyzers_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/boost_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/boost_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/boost_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/boost_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/coerce_number_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/coerce_number_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/coerce_number_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/coerce_number_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/coerce_shape_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/coerce_shape_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/coerce_shape_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/coerce_shape_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/copy_to_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/copy_to_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/copy_to_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/copy_to_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/doc_values_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/doc_values_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/doc_values_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/doc_values_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/dynamic_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/dynamic_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/dynamic_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/dynamic_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/eager_global_ordinals_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/eager_global_ordinals_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/eager_global_ordinals_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/eager_global_ordinals_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/enabled_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/enabled_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/enabled_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/enabled_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_frequency_filter_absolute.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_frequency_filter_absolute.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_frequency_filter_absolute.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_frequency_filter_absolute.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_frequency_filter_percentage.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_frequency_filter_percentage.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_frequency_filter_percentage.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_frequency_filter_percentage.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/fielddata_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/format_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/format_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/format_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/format_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/ignore_malformed.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/ignore_malformed.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/ignore_malformed.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/ignore_malformed.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/ignore_z_value_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/ignore_z_value_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/ignore_z_value_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/ignore_z_value_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/index_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/locale_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/locale_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/locale_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/locale_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/max_shingle_size_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/max_shingle_size_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/max_shingle_size_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/max_shingle_size_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/name_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/name_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/name_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/name_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/norms_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/norms_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/norms_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/norms_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/null_value_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/null_value_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/null_value_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/null_value_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/orientation_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/orientation_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/orientation_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/orientation_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/path_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/path_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/path_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/path_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/relations_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/relations_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/relations_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/relations_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/similarity_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/similarity_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/similarity_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/similarity_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/split_queries_on_whitespace_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/split_queries_on_whitespace_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/split_queries_on_whitespace_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/split_queries_on_whitespace_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/store_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/store_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/store_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/store_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/term_vector_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/term_vector_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/term_vector_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/term_vector_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/type_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/type_parameter.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/type_parameter.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/type_parameter.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/_field_list_item.scss b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/_field_list_item.scss similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/_field_list_item.scss rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/_field_list_item.scss diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/_index.scss b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/_index.scss similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/_index.scss rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/_index.scss diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx similarity index 83% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx index 5f1b8c0df770e..60b025ce644ef 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx @@ -66,7 +66,7 @@ export const CreateField = React.memo(function CreateFieldComponent({ }); return subscription.unsubscribe; - }, [form]); + }, [form, dispatch]); const cancel = () => { dispatch({ type: 'documentField.changeStatus', value: 'idle' }); @@ -108,43 +108,53 @@ export const CreateField = React.memo(function CreateFieldComponent({ * * @param type The selected field type */ - const getSubTypeMeta = ( - type: MainType - ): { subTypeLabel?: string; subTypeOptions?: ComboBoxOption[] } => { - const typeDefinition = TYPE_DEFINITION[type]; - const hasSubTypes = typeDefinition !== undefined && typeDefinition.subTypes; - - let subTypeOptions = hasSubTypes - ? typeDefinition - .subTypes!.types.map(subType => TYPE_DEFINITION[subType]) - .map( - subType => ({ value: subType.value as SubType, label: subType.label } as ComboBoxOption) - ) - : undefined; - - if (hasSubTypes) { - if (isMultiField) { - // If it is a multi-field, we need to filter out non-allowed types - subTypeOptions = filterTypesForMultiField(subTypeOptions!); - } else if (isRootLevelField === false) { - subTypeOptions = filterTypesForNonRootFields(subTypeOptions!); + const getSubTypeMeta = useCallback( + ( + type: MainType + ): { + subTypeLabel?: string; + subTypeOptions?: ComboBoxOption[]; + } => { + const typeDefinition = TYPE_DEFINITION[type]; + const hasSubTypes = typeDefinition !== undefined && typeDefinition.subTypes; + + let subTypeOptions = hasSubTypes + ? typeDefinition + .subTypes!.types.map(subType => TYPE_DEFINITION[subType]) + .map( + subType => + ({ value: subType.value as SubType, label: subType.label } as ComboBoxOption) + ) + : undefined; + + if (hasSubTypes) { + if (isMultiField) { + // If it is a multi-field, we need to filter out non-allowed types + subTypeOptions = filterTypesForMultiField(subTypeOptions!); + } else if (isRootLevelField === false) { + subTypeOptions = filterTypesForNonRootFields(subTypeOptions!); + } } - } - return { - subTypeOptions, - subTypeLabel: hasSubTypes ? typeDefinition.subTypes!.label : undefined, - }; - }; + return { + subTypeOptions, + subTypeLabel: hasSubTypes ? typeDefinition.subTypes!.label : undefined, + }; + }, + [isMultiField, isRootLevelField] + ); - const onTypeChange = (nextType: ComboBoxOption[]) => { - form.setFieldValue('type', nextType); + const onTypeChange = useCallback( + (nextType: ComboBoxOption[]) => { + form.setFieldValue('type', nextType); - if (nextType.length) { - const { subTypeOptions } = getSubTypeMeta(nextType[0].value as MainType); - form.setFieldValue('subType', subTypeOptions ? [subTypeOptions[0]] : undefined); - } - }; + if (nextType.length) { + const { subTypeOptions } = getSubTypeMeta(nextType[0].value as MainType); + form.setFieldValue('subType', subTypeOptions ? [subTypeOptions[0]] : undefined); + } + }, + [form, getSubTypeMeta] + ); const renderFormFields = useCallback( ({ type }) => { @@ -208,7 +218,7 @@ export const CreateField = React.memo(function CreateFieldComponent({
); }, - [form, isMultiField] + [getSubTypeMeta, isMultiField, isRootLevelField, onTypeChange] ); const renderFormActions = () => ( diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/alias_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/alias_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/alias_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/alias_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/dense_vector_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/dense_vector_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/dense_vector_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/dense_vector_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/scaled_float_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/scaled_float_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/scaled_float_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/scaled_float_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/token_count_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/token_count_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/token_count_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/required_parameters_forms/token_count_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/delete_field_provider.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/delete_field_provider.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/delete_field_provider.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/delete_field_provider.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/_edit_field_form_row.scss b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/_edit_field_form_row.scss similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/_edit_field_form_row.scss rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/_edit_field_form_row.scss diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/_index.scss b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/_index.scss similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/_index.scss rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/_index.scss diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/advanced_parameters_section.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/advanced_parameters_section.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/advanced_parameters_section.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/advanced_parameters_section.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/basic_parameters_section.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/basic_parameters_section.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/basic_parameters_section.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/basic_parameters_section.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_container.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_container.tsx similarity index 97% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_container.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_container.tsx index 284ae8803acb5..1f77584439568 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_container.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_container.tsx @@ -32,11 +32,11 @@ export const EditFieldContainer = React.memo(({ field, allFields }: Props) => { }); return subscription.unsubscribe; - }, [form]); + }, [form, dispatch]); const exitEdit = useCallback(() => { dispatch({ type: 'documentField.changeStatus', value: 'idle' }); - }, []); + }, [dispatch]); return ; }); diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_form_row.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_form_row.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_form_row.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_form_row.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_header_form.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_header_form.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_header_form.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/edit_field_header_form.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/field_description_section.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/field_description_section.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/field_description_section.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/field_description_section.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/update_field_provider.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/update_field_provider.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/update_field_provider.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/edit_field/update_field_provider.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/alias_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/alias_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/alias_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/alias_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/binary_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/binary_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/binary_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/binary_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/boolean_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/boolean_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/boolean_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/boolean_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/completion_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/completion_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/completion_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/completion_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/date_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/date_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/date_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/date_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/dense_vector_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/dense_vector_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/dense_vector_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/dense_vector_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/flattened_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/flattened_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/flattened_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/flattened_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/geo_point_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/geo_point_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/geo_point_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/geo_point_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/geo_shape_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/geo_shape_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/geo_shape_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/geo_shape_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/ip_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/ip_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/ip_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/ip_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/join_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/join_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/join_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/join_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/keyword_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/keyword_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/keyword_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/keyword_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/nested_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/nested_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/nested_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/nested_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/numeric_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/numeric_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/numeric_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/numeric_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/object_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/object_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/object_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/object_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/range_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/range_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/range_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/range_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/search_as_you_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/search_as_you_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/search_as_you_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/search_as_you_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/shape_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/shape_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/shape_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/shape_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/text_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/text_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/text_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/text_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/token_count_type.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/token_count_type.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/token_count_type.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/field_types/token_count_type.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item_container.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item_container.tsx similarity index 92% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item_container.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item_container.tsx index cff2d294fead9..55093e606cfa1 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item_container.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item_container.tsx @@ -23,7 +23,7 @@ export const FieldsListItemContainer = ({ fieldId, treeDepth, isLastItem }: Prop fields: { byId, maxNestedDepth }, } = useMappingsState(); - const getField = (id: string) => byId[id]; + const getField = useCallback((id: string) => byId[id], [byId]); const field: NormalizedField = getField(fieldId); const { childFields } = field; @@ -33,7 +33,7 @@ export const FieldsListItemContainer = ({ fieldId, treeDepth, isLastItem }: Prop const areActionButtonsVisible = status === 'idle'; const childFieldsArray = useMemo( () => (childFields !== undefined ? childFields.map(getField) : []), - [childFields] + [childFields, getField] ); const addField = useCallback(() => { @@ -41,18 +41,18 @@ export const FieldsListItemContainer = ({ fieldId, treeDepth, isLastItem }: Prop type: 'documentField.createField', value: fieldId, }); - }, [fieldId]); + }, [fieldId, dispatch]); const editField = useCallback(() => { dispatch({ type: 'documentField.editField', value: fieldId, }); - }, [fieldId]); + }, [fieldId, dispatch]); const toggleExpand = useCallback(() => { dispatch({ type: 'field.toggleExpand', value: { fieldId } }); - }, [fieldId]); + }, [fieldId, dispatch]); return ( { documentFields: { status, fieldToAddFieldTo }, } = useMappingsState(); - const getField = (fieldId: string) => byId[fieldId]; - const fields = useMemo(() => rootLevelFields.map(getField), [rootLevelFields]); + const getField = useCallback((fieldId: string) => byId[fieldId], [byId]); + const fields = useMemo(() => rootLevelFields.map(getField), [rootLevelFields, getField]); - const addField = () => { + const addField = useCallback(() => { dispatch({ type: 'documentField.createField' }); - }; + }, [dispatch]); useEffect(() => { /** @@ -32,7 +32,7 @@ export const DocumentFieldsTreeEditor = () => { if (status === 'idle' && fields.length === 0) { addField(); } - }, [fields, status]); + }, [addField, fields, status]); const renderCreateField = () => { // The "fieldToAddFieldTo" is undefined when adding to the top level "properties" object. diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/search_fields/search_result_item.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/fields_tree.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/fields_tree.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/fields_tree.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/fields_tree.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_from_json_button.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_from_json_button.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_from_json_button.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_from_json_button.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.test.tsx similarity index 98% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.test.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.test.tsx index a9433d3a7530f..f8e3eca7898d2 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.test.tsx @@ -19,7 +19,7 @@ jest.mock('@elastic/eui', () => ({ ), })); -import { registerTestBed, nextTick, TestBed } from '../../../../../../../../../test_utils'; +import { registerTestBed, nextTick, TestBed } from '../../../../../../../../test_utils'; import { LoadMappingsProvider } from './load_mappings_provider'; const ComponentToTest = ({ onJson }: { onJson: () => void }) => ( diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/load_mappings/load_mappings_provider.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/multiple_mappings_warning.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/multiple_mappings_warning.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/multiple_mappings_warning.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/multiple_mappings_warning.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/templates_form/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/templates_form/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/templates_form/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/templates_form/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/templates_form/templates_form.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/templates_form/templates_form.tsx similarity index 98% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/templates_form/templates_form.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/templates_form/templates_form.tsx index 471217108ba6f..f32fcb3956e1c 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/templates_form/templates_form.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/templates_form/templates_form.tsx @@ -69,7 +69,7 @@ export const TemplatesForm = React.memo(({ defaultValue }: Props) => { }); }); return subscription.unsubscribe; - }, [form]); + }, [form, dispatch]); useEffect(() => { if (didMountRef.current) { @@ -80,14 +80,14 @@ export const TemplatesForm = React.memo(({ defaultValue }: Props) => { // Avoid reseting the form on component mount. didMountRef.current = true; } - }, [defaultValue]); + }, [defaultValue, form]); useEffect(() => { return () => { // On unmount => save in the state a snapshot of the current form data. dispatch({ type: 'templates.save' }); }; - }, []); + }, [dispatch]); return ( <> diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/templates_form/templates_form_schema.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/templates_form/templates_form_schema.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/templates_form/templates_form_schema.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/templates_form/templates_form_schema.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/tree/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/tree/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/tree/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/tree/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/tree/tree.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/tree/tree.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/tree/tree.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/tree/tree.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/tree/tree_item.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/tree/tree_item.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/components/tree/tree_item.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/components/tree/tree_item.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/constants/data_types_definition.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/default_values.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/default_values.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/default_values.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/constants/default_values.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/field_options.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/field_options.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/field_options.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/constants/field_options.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/field_options_i18n.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/field_options_i18n.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/field_options_i18n.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/constants/field_options_i18n.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/constants/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/mappings_editor.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/mappings_editor.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/mappings_editor.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/constants/mappings_editor.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/parameters_definition.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/parameters_definition.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/constants/parameters_definition.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/constants/parameters_definition.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/index_settings_context.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/index_settings_context.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/index_settings_context.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/index_settings_context.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/error_reporter.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/error_reporter.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/error_reporter.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/lib/error_reporter.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/extract_mappings_definition.test.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/extract_mappings_definition.test.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/extract_mappings_definition.test.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/lib/extract_mappings_definition.test.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/extract_mappings_definition.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/extract_mappings_definition.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/extract_mappings_definition.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/lib/extract_mappings_definition.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/index.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/index.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/lib/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/mappings_validator.test.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/mappings_validator.test.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/mappings_validator.test.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/lib/mappings_validator.test.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/mappings_validator.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/mappings_validator.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/mappings_validator.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/lib/mappings_validator.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.test.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.test.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.test.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.test.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/lib/search_fields.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/serializers.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/serializers.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/serializers.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/lib/serializers.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/validators.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/validators.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/lib/validators.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/lib/validators.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/mappings_editor.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_editor.tsx similarity index 98% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/mappings_editor.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_editor.tsx index d79a023386e8d..b6345a7140e15 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/mappings_editor.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_editor.tsx @@ -78,7 +78,7 @@ export const MappingsEditor = React.memo(({ onUpdate, defaultValue, indexSetting isValid: true, }); } - }, [multipleMappingsDeclared]); + }, [multipleMappingsDeclared, onUpdate, defaultValue]); const changeTab = async (tab: TabName, state: State) => { if (selectedTab === 'advanced') { diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/mappings_state.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_state.tsx similarity index 98% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/mappings_state.tsx rename to x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_state.tsx index 65a1aa2858d14..247bd183baddf 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/mappings_state.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_state.tsx @@ -168,7 +168,7 @@ export const MappingsState = React.memo(({ children, onUpdate, defaultValue }: P }, isValid: state.isValid, }); - }, [state]); + }, [state, onUpdate]); useEffect(() => { /** @@ -187,7 +187,7 @@ export const MappingsState = React.memo(({ children, onUpdate, defaultValue }: P } else { didMountRef.current = true; } - }, [defaultValue]); + }, [defaultValue, parsedFieldsDefaultValue]); return ( diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/reducer.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/reducer.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/reducer.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/reducer.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/shared_imports.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/shared_imports.ts similarity index 72% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/shared_imports.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/shared_imports.ts index e99d8840d57df..2979015c07455 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/shared_imports.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/shared_imports.ts @@ -24,7 +24,7 @@ export { VALIDATION_TYPES, ValidationFunc, ValidationFuncArg, -} from '../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib'; +} from '../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib'; export { CheckBoxField, @@ -39,14 +39,14 @@ export { ComboBoxField, ToggleField, JsonEditorField, -} from '../../../../../../../../src/plugins/es_ui_shared/static/forms/components'; +} from '../../../../../../../src/plugins/es_ui_shared/static/forms/components'; export { fieldFormatters, fieldValidators, -} from '../../../../../../../../src/plugins/es_ui_shared/static/forms/helpers'; +} from '../../../../../../../src/plugins/es_ui_shared/static/forms/helpers'; export { JsonEditor, OnJsonEditorUpdateHandler, -} from '../../../../../../../../src/plugins/es_ui_shared/public'; +} from '../../../../../../../src/plugins/es_ui_shared/public'; diff --git a/x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/types.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/types.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/mappings_editor/types.ts rename to x-pack/plugins/index_management/public/application/components/mappings_editor/types.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/no_match/index.ts b/x-pack/plugins/index_management/public/application/components/no_match/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/no_match/index.ts rename to x-pack/plugins/index_management/public/application/components/no_match/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/no_match/no_match.tsx b/x-pack/plugins/index_management/public/application/components/no_match/no_match.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/no_match/no_match.tsx rename to x-pack/plugins/index_management/public/application/components/no_match/no_match.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/page_error/index.ts b/x-pack/plugins/index_management/public/application/components/page_error/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/page_error/index.ts rename to x-pack/plugins/index_management/public/application/components/page_error/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/page_error/page_error_forbidden.tsx b/x-pack/plugins/index_management/public/application/components/page_error/page_error_forbidden.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/page_error/page_error_forbidden.tsx rename to x-pack/plugins/index_management/public/application/components/page_error/page_error_forbidden.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/section_error.tsx b/x-pack/plugins/index_management/public/application/components/section_error.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/section_error.tsx rename to x-pack/plugins/index_management/public/application/components/section_error.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/section_loading.tsx b/x-pack/plugins/index_management/public/application/components/section_loading.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/section_loading.tsx rename to x-pack/plugins/index_management/public/application/components/section_loading.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_delete_modal.tsx b/x-pack/plugins/index_management/public/application/components/template_delete_modal.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/template_delete_modal.tsx rename to x-pack/plugins/index_management/public/application/components/template_delete_modal.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_form/index.ts b/x-pack/plugins/index_management/public/application/components/template_form/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/template_form/index.ts rename to x-pack/plugins/index_management/public/application/components/template_form/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/index.ts b/x-pack/plugins/index_management/public/application/components/template_form/steps/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/index.ts rename to x-pack/plugins/index_management/public/application/components/template_form/steps/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/step_aliases.tsx b/x-pack/plugins/index_management/public/application/components/template_form/steps/step_aliases.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/step_aliases.tsx rename to x-pack/plugins/index_management/public/application/components/template_form/steps/step_aliases.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/step_logistics.tsx b/x-pack/plugins/index_management/public/application/components/template_form/steps/step_logistics.tsx similarity index 94% rename from x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/step_logistics.tsx rename to x-pack/plugins/index_management/public/application/components/template_form/steps/step_logistics.tsx index dd8d49a569042..2f6e055b5d0c6 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/step_logistics.tsx +++ b/x-pack/plugins/index_management/public/application/components/template_form/steps/step_logistics.tsx @@ -7,15 +7,8 @@ import React, { useEffect } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiButtonEmpty, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { - useForm, - Form, - getUseField, -} from '../../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib'; -import { - getFormRow, - Field, -} from '../../../../../../../../../src/plugins/es_ui_shared/static/forms/components'; + +import { useForm, Form, getUseField, getFormRow, Field } from '../../../../shared_imports'; import { documentationService } from '../../../services/documentation'; import { StepProps } from '../types'; import { schemas, nameConfig, nameConfigWithoutValidations } from '../template_form_schemas'; @@ -80,11 +73,11 @@ export const StepLogistics: React.FunctionComponent = ({ useEffect(() => { onStepValidityChange(form.isValid); - }, [form.isValid]); + }, [form.isValid, onStepValidityChange]); useEffect(() => { setDataGetter(form.submit); - }, [form]); + }, [form.submit, setDataGetter]); const { name, indexPatterns, order, version } = fieldsMeta; diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/step_mappings.tsx b/x-pack/plugins/index_management/public/application/components/template_form/steps/step_mappings.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/step_mappings.tsx rename to x-pack/plugins/index_management/public/application/components/template_form/steps/step_mappings.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/step_review.tsx b/x-pack/plugins/index_management/public/application/components/template_form/steps/step_review.tsx similarity index 98% rename from x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/step_review.tsx rename to x-pack/plugins/index_management/public/application/components/template_form/steps/step_review.tsx index 09172bf5cd0ca..09da43b83c3c5 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/step_review.tsx +++ b/x-pack/plugins/index_management/public/application/components/template_form/steps/step_review.tsx @@ -20,7 +20,7 @@ import { EuiCodeBlock, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { serializers } from '../../../../../../../../../src/plugins/es_ui_shared/static/forms/helpers'; +import { serializers } from '../../../../shared_imports'; import { serializeTemplate } from '../../../../../common/lib/template_serialization'; import { Template } from '../../../../../common/types'; diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/step_settings.tsx b/x-pack/plugins/index_management/public/application/components/template_form/steps/step_settings.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/step_settings.tsx rename to x-pack/plugins/index_management/public/application/components/template_form/steps/step_settings.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/use_json_step.ts b/x-pack/plugins/index_management/public/application/components/template_form/steps/use_json_step.ts similarity index 83% rename from x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/use_json_step.ts rename to x-pack/plugins/index_management/public/application/components/template_form/steps/use_json_step.ts index ae16a2e9263ff..fbe479ea0cf23 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/template_form/steps/use_json_step.ts +++ b/x-pack/plugins/index_management/public/application/components/template_form/steps/use_json_step.ts @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { useEffect, useState } from 'react'; +import { useEffect, useState, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; -import { isJSON } from '../../../../../../../../../src/plugins/es_ui_shared/static/validators/string'; +import { isJSON } from '../../../../shared_imports'; import { StepProps } from '../types'; interface Parameters { @@ -29,7 +29,7 @@ export const useJsonStep = ({ const [content, setContent] = useState(stringifyJson(defaultValue)); const [error, setError] = useState(null); - const validateContent = () => { + const validateContent = useCallback(() => { // We allow empty string as it will be converted to "{}"" const isValid = content.trim() === '' ? true : isJSON(content); if (!isValid) { @@ -42,20 +42,20 @@ export const useJsonStep = ({ setError(null); } return isValid; - }; + }, [content]); - const dataGetter = () => { + const dataGetter = useCallback(() => { const isValid = validateContent(); const value = isValid && content.trim() !== '' ? JSON.parse(content) : {}; const data = { [prop]: value }; return Promise.resolve({ isValid, data }); - }; + }, [content, validateContent, prop]); useEffect(() => { const isValid = validateContent(); onStepValidityChange(isValid); setDataGetter(dataGetter); - }, [content]); + }, [content, dataGetter, onStepValidityChange, setDataGetter, validateContent]); return { content, diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_form/template_form.tsx b/x-pack/plugins/index_management/public/application/components/template_form/template_form.tsx similarity index 92% rename from x-pack/legacy/plugins/index_management/public/application/components/template_form/template_form.tsx rename to x-pack/plugins/index_management/public/application/components/template_form/template_form.tsx index 6a76e1d203b70..58be9b2c63365 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/template_form/template_form.tsx +++ b/x-pack/plugins/index_management/public/application/components/template_form/template_form.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useState, useRef } from 'react'; +import React, { Fragment, useState, useRef, useCallback } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, @@ -14,7 +14,7 @@ import { EuiSpacer, } from '@elastic/eui'; -import { serializers } from '../../../../../../../../src/plugins/es_ui_shared/static/forms/helpers'; +import { serializers } from '../../../shared_imports'; import { Template } from '../../../../common/types'; import { TemplateSteps } from './template_steps'; import { StepAliases, StepLogistics, StepMappings, StepSettings, StepReview } from './steps'; @@ -70,19 +70,25 @@ export const TemplateForm: React.FunctionComponent = ({ const CurrentStepComponent = stepComponentMap[currentStep]; const isStepValid = validation[currentStep].isValid; - const setStepDataGetter = (stepDataGetter: DataGetterFunc) => { - stepsDataGetters.current[currentStep] = stepDataGetter; - }; + const setStepDataGetter = useCallback( + (stepDataGetter: DataGetterFunc) => { + stepsDataGetters.current[currentStep] = stepDataGetter; + }, + [currentStep] + ); - const onStepValidityChange = (isValid: boolean | undefined) => { - setValidation(prev => ({ - ...prev, - [currentStep]: { - isValid, - errors: {}, - }, - })); - }; + const onStepValidityChange = useCallback( + (isValid: boolean | undefined) => { + setValidation(prev => ({ + ...prev, + [currentStep]: { + isValid, + errors: {}, + }, + })); + }, + [currentStep] + ); const validateAndGetDataFromCurrentStep = async () => { const validateAndGetData = stepsDataGetters.current[currentStep]; diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_form/template_form_schemas.tsx b/x-pack/plugins/index_management/public/application/components/template_form/template_form_schemas.tsx similarity index 96% rename from x-pack/legacy/plugins/index_management/public/application/components/template_form/template_form_schemas.tsx rename to x-pack/plugins/index_management/public/application/components/template_form/template_form_schemas.tsx index ed2616cc64e38..9ff73b71adf50 100644 --- a/x-pack/legacy/plugins/index_management/public/application/components/template_form/template_form_schemas.tsx +++ b/x-pack/plugins/index_management/public/application/components/template_form/template_form_schemas.tsx @@ -13,12 +13,9 @@ import { FIELD_TYPES, VALIDATION_TYPES, FieldConfig, -} from '../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib'; - -import { fieldFormatters, fieldValidators, -} from '../../../../../../../../src/plugins/es_ui_shared/static/forms/helpers'; +} from '../../../shared_imports'; import { INVALID_INDEX_PATTERN_CHARS, diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_form/template_steps.tsx b/x-pack/plugins/index_management/public/application/components/template_form/template_steps.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/template_form/template_steps.tsx rename to x-pack/plugins/index_management/public/application/components/template_form/template_steps.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/components/template_form/types.ts b/x-pack/plugins/index_management/public/application/components/template_form/types.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/components/template_form/types.ts rename to x-pack/plugins/index_management/public/application/components/template_form/types.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/constants/detail_panel_tabs.ts b/x-pack/plugins/index_management/public/application/constants/detail_panel_tabs.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/constants/detail_panel_tabs.ts rename to x-pack/plugins/index_management/public/application/constants/detail_panel_tabs.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/constants/index.ts b/x-pack/plugins/index_management/public/application/constants/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/constants/index.ts rename to x-pack/plugins/index_management/public/application/constants/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/constants/refresh_intervals.ts b/x-pack/plugins/index_management/public/application/constants/refresh_intervals.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/constants/refresh_intervals.ts rename to x-pack/plugins/index_management/public/application/constants/refresh_intervals.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/index.tsx b/x-pack/plugins/index_management/public/application/index.tsx similarity index 94% rename from x-pack/legacy/plugins/index_management/public/application/index.tsx rename to x-pack/plugins/index_management/public/application/index.tsx index b9859903f1434..5850cb8d42f1a 100644 --- a/x-pack/legacy/plugins/index_management/public/application/index.tsx +++ b/x-pack/plugins/index_management/public/application/index.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { Provider } from 'react-redux'; import { render, unmountComponentAtNode } from 'react-dom'; -import { CoreStart } from '../../../../../../src/core/public'; +import { CoreStart } from '../../../../../src/core/public'; import { AppContextProvider, AppDependencies } from './app_context'; import { App } from './app'; diff --git a/x-pack/legacy/plugins/index_management/public/application/lib/ace.js b/x-pack/plugins/index_management/public/application/lib/ace.js similarity index 94% rename from x-pack/legacy/plugins/index_management/public/application/lib/ace.js rename to x-pack/plugins/index_management/public/application/lib/ace.js index b9620dfbdb120..3b37c8fb8870e 100644 --- a/x-pack/legacy/plugins/index_management/public/application/lib/ace.js +++ b/x-pack/plugins/index_management/public/application/lib/ace.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import ace from 'ace'; +import brace from 'brace'; import 'brace/ext/language_tools'; const splitTokens = line => { @@ -43,14 +43,14 @@ const wordCompleter = words => { }; export const createAceEditor = (div, value, readOnly = true, autocompleteArray) => { - const editor = ace.edit(div); + const editor = brace.edit(div); editor.$blockScrolling = Infinity; editor.setValue(value, -1); const session = editor.getSession(); session.setUseWrapMode(true); session.setMode('ace/mode/json'); if (autocompleteArray) { - const languageTools = ace.acequire('ace/ext/language_tools'); + const languageTools = brace.acequire('ace/ext/language_tools'); const autocompleter = wordCompleter(autocompleteArray); languageTools.setCompleters([autocompleter]); } diff --git a/x-pack/legacy/plugins/index_management/public/application/lib/edit_settings.js b/x-pack/plugins/index_management/public/application/lib/edit_settings.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/lib/edit_settings.js rename to x-pack/plugins/index_management/public/application/lib/edit_settings.js diff --git a/x-pack/legacy/plugins/index_management/public/application/lib/flatten_object.js b/x-pack/plugins/index_management/public/application/lib/flatten_object.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/lib/flatten_object.js rename to x-pack/plugins/index_management/public/application/lib/flatten_object.js diff --git a/x-pack/legacy/plugins/index_management/public/application/lib/flatten_panel_tree.js b/x-pack/plugins/index_management/public/application/lib/flatten_panel_tree.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/lib/flatten_panel_tree.js rename to x-pack/plugins/index_management/public/application/lib/flatten_panel_tree.js diff --git a/x-pack/legacy/plugins/index_management/public/application/lib/index_status_labels.js b/x-pack/plugins/index_management/public/application/lib/index_status_labels.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/lib/index_status_labels.js rename to x-pack/plugins/index_management/public/application/lib/index_status_labels.js diff --git a/x-pack/legacy/plugins/index_management/public/application/lib/manage_angular_lifecycle.ts b/x-pack/plugins/index_management/public/application/lib/manage_angular_lifecycle.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/lib/manage_angular_lifecycle.ts rename to x-pack/plugins/index_management/public/application/lib/manage_angular_lifecycle.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/lib/render_badges.js b/x-pack/plugins/index_management/public/application/lib/render_badges.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/lib/render_badges.js rename to x-pack/plugins/index_management/public/application/lib/render_badges.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/home.tsx b/x-pack/plugins/index_management/public/application/sections/home/home.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/home.tsx rename to x-pack/plugins/index_management/public/application/sections/home/home.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index.ts b/x-pack/plugins/index_management/public/application/sections/home/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index.ts rename to x-pack/plugins/index_management/public/application/sections/home/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/detail_panel.container.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/detail_panel.container.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/detail_panel.container.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/detail_panel.container.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/detail_panel.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/detail_panel.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/detail_panel.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/detail_panel.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/edit_settings_json.container.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/edit_settings_json.container.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/edit_settings_json.container.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/edit_settings_json.container.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/edit_settings_json.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/edit_settings_json.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/edit_settings_json.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/edit_settings_json.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/index.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/index.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/index.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/edit_settings_json/index.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/index.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/index.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/index.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/index.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/index.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/index.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/index.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/index.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/show_json.container.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/show_json.container.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/show_json.container.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/show_json.container.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/show_json.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/show_json.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/show_json.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/show_json/show_json.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/index.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/index.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/index.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/index.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/summary.container.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/summary.container.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/summary.container.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/summary.container.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/summary.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/summary.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/summary.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/detail_panel/summary/summary.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index.ts b/x-pack/plugins/index_management/public/application/sections/home/index_list/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index.ts rename to x-pack/plugins/index_management/public/application/sections/home/index_list/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.container.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.container.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.container.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.container.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_list.d.ts b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_list.d.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_list.d.ts rename to x-pack/plugins/index_management/public/application/sections/home/index_list/index_list.d.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_list.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_list.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_list.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/index_list.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_table/index.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_table/index.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.container.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.container.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.container.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.container.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js rename to x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/index.ts b/x-pack/plugins/index_management/public/application/sections/home/template_list/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/index.ts rename to x-pack/plugins/index_management/public/application/sections/home/template_list/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/index.ts b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/index.ts rename to x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/index.ts b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/index.ts rename to x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_aliases.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_aliases.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_aliases.tsx rename to x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_aliases.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_mappings.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_mappings.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_mappings.tsx rename to x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_mappings.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_settings.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_settings.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_settings.tsx rename to x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_settings.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx rename to x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/template_details.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/template_details.tsx similarity index 98% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/template_details.tsx rename to x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/template_details.tsx index ced8bd97e744b..9c31b0d650449 100644 --- a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_details/template_details.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/template_details.tsx @@ -32,7 +32,7 @@ import { } from '../../../../../../common/constants'; import { Template } from '../../../../../../common/types'; import { TemplateDeleteModal, SectionLoading, SectionError, Error } from '../../../../components'; -import { loadIndexTemplate } from '../../../../services/api'; +import { useLoadIndexTemplate } from '../../../../services/api'; import { decodePath } from '../../../../services/routing'; import { SendRequestResponse } from '../../../../../shared_imports'; import { useServices } from '../../../../app_context'; @@ -103,7 +103,7 @@ export const TemplateDetails: React.FunctionComponent = ({ }) => { const { uiMetricService } = useServices(); const decodedTemplateName = decodePath(templateName); - const { error, data: templateDetails, isLoading } = loadIndexTemplate(decodedTemplateName); + const { error, data: templateDetails, isLoading } = useLoadIndexTemplate(decodedTemplateName); // TS complains if we use destructuring here. Fixed in 3.6.0 (https://github.com/microsoft/TypeScript/pull/31711). const isManaged = templateDetails ? templateDetails.isManaged : undefined; const [templateToDelete, setTemplateToDelete] = useState>([]); diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_list.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_list.tsx similarity index 97% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_list.tsx rename to x-pack/plugins/index_management/public/application/sections/home/template_list/template_list.tsx index 71c32e2e0177f..ffdb224f16271 100644 --- a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_list.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_list.tsx @@ -18,7 +18,7 @@ import { } from '@elastic/eui'; import { SectionError, SectionLoading, Error } from '../../../components'; import { TemplateTable } from './template_table'; -import { loadIndexTemplates } from '../../../services/api'; +import { useLoadIndexTemplates } from '../../../services/api'; import { Template } from '../../../../../common/types'; import { useServices } from '../../../app_context'; import { @@ -40,7 +40,7 @@ export const TemplateList: React.FunctionComponent { const { uiMetricService } = useServices(); - const { error, isLoading, data: templates, sendRequest: reload } = loadIndexTemplates(); + const { error, isLoading, data: templates, sendRequest: reload } = useLoadIndexTemplates(); let content; @@ -68,7 +68,7 @@ export const TemplateList: React.FunctionComponent { uiMetricService.trackMetric('loaded', UIM_TEMPLATE_LIST_LOAD); - }, []); + }, [uiMetricService]); if (isLoading) { content = ( diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_table/index.ts b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_table/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_table/index.ts rename to x-pack/plugins/index_management/public/application/sections/home/template_list/template_table/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_table/template_table.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_table/template_table.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/home/template_list/template_table/template_table.tsx rename to x-pack/plugins/index_management/public/application/sections/home/template_list/template_table/template_table.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/template_clone/index.ts b/x-pack/plugins/index_management/public/application/sections/template_clone/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/template_clone/index.ts rename to x-pack/plugins/index_management/public/application/sections/template_clone/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/template_clone/template_clone.tsx b/x-pack/plugins/index_management/public/application/sections/template_clone/template_clone.tsx similarity index 96% rename from x-pack/legacy/plugins/index_management/public/application/sections/template_clone/template_clone.tsx rename to x-pack/plugins/index_management/public/application/sections/template_clone/template_clone.tsx index 6659be5a2cf4e..cf6ca3c065777 100644 --- a/x-pack/legacy/plugins/index_management/public/application/sections/template_clone/template_clone.tsx +++ b/x-pack/plugins/index_management/public/application/sections/template_clone/template_clone.tsx @@ -11,7 +11,7 @@ import { TemplateForm, SectionLoading, SectionError, Error } from '../../compone import { breadcrumbService } from '../../services/breadcrumbs'; import { decodePath, getTemplateDetailsLink } from '../../services/routing'; import { Template } from '../../../../common/types'; -import { saveTemplate, loadIndexTemplate } from '../../services/api'; +import { saveTemplate, useLoadIndexTemplate } from '../../services/api'; interface MatchParams { name: string; @@ -27,7 +27,7 @@ export const TemplateClone: React.FunctionComponent(false); const [saveError, setSaveError] = useState(null); - const { error: templateToCloneError, data: templateToClone, isLoading } = loadIndexTemplate( + const { error: templateToCloneError, data: templateToClone, isLoading } = useLoadIndexTemplate( decodedTemplateName ); diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/template_create/index.ts b/x-pack/plugins/index_management/public/application/sections/template_create/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/template_create/index.ts rename to x-pack/plugins/index_management/public/application/sections/template_create/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/template_create/template_create.tsx b/x-pack/plugins/index_management/public/application/sections/template_create/template_create.tsx similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/template_create/template_create.tsx rename to x-pack/plugins/index_management/public/application/sections/template_create/template_create.tsx diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/template_edit/index.ts b/x-pack/plugins/index_management/public/application/sections/template_edit/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/sections/template_edit/index.ts rename to x-pack/plugins/index_management/public/application/sections/template_edit/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/sections/template_edit/template_edit.tsx b/x-pack/plugins/index_management/public/application/sections/template_edit/template_edit.tsx similarity index 96% rename from x-pack/legacy/plugins/index_management/public/application/sections/template_edit/template_edit.tsx rename to x-pack/plugins/index_management/public/application/sections/template_edit/template_edit.tsx index 69e446528a68d..1e9d5f294de34 100644 --- a/x-pack/legacy/plugins/index_management/public/application/sections/template_edit/template_edit.tsx +++ b/x-pack/plugins/index_management/public/application/sections/template_edit/template_edit.tsx @@ -8,7 +8,7 @@ import { RouteComponentProps } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiPageBody, EuiPageContent, EuiTitle, EuiSpacer, EuiCallOut } from '@elastic/eui'; import { breadcrumbService } from '../../services/breadcrumbs'; -import { loadIndexTemplate, updateTemplate } from '../../services/api'; +import { useLoadIndexTemplate, updateTemplate } from '../../services/api'; import { decodePath, getTemplateDetailsLink } from '../../services/routing'; import { SectionLoading, SectionError, TemplateForm, Error } from '../../components'; import { Template } from '../../../../common/types'; @@ -27,7 +27,7 @@ export const TemplateEdit: React.FunctionComponent(false); const [saveError, setSaveError] = useState(null); - const { error, data: template, isLoading } = loadIndexTemplate(decodedTemplateName); + const { error, data: template, isLoading } = useLoadIndexTemplate(decodedTemplateName); useEffect(() => { breadcrumbService.setBreadcrumbs('templateEdit'); diff --git a/x-pack/legacy/plugins/index_management/public/application/services/api.ts b/x-pack/plugins/index_management/public/application/services/api.ts similarity index 98% rename from x-pack/legacy/plugins/index_management/public/application/services/api.ts rename to x-pack/plugins/index_management/public/application/services/api.ts index 642fd441b353a..88887f40972e4 100644 --- a/x-pack/legacy/plugins/index_management/public/application/services/api.ts +++ b/x-pack/plugins/index_management/public/application/services/api.ts @@ -200,7 +200,7 @@ export async function loadIndexData(type: string, indexName: string) { } } -export function loadIndexTemplates() { +export function useLoadIndexTemplates() { return useRequest({ path: `${API_BASE_PATH}/templates`, method: 'get', @@ -220,7 +220,7 @@ export async function deleteTemplates(names: Array) { return result; } -export function loadIndexTemplate(name: Template['name']) { +export function useLoadIndexTemplate(name: Template['name']) { return useRequest({ path: `${API_BASE_PATH}/templates/${encodeURIComponent(name)}`, method: 'get', diff --git a/x-pack/legacy/plugins/index_management/public/application/services/breadcrumbs.ts b/x-pack/plugins/index_management/public/application/services/breadcrumbs.ts similarity index 96% rename from x-pack/legacy/plugins/index_management/public/application/services/breadcrumbs.ts rename to x-pack/plugins/index_management/public/application/services/breadcrumbs.ts index 299491756560e..8128ccd545dce 100644 --- a/x-pack/legacy/plugins/index_management/public/application/services/breadcrumbs.ts +++ b/x-pack/plugins/index_management/public/application/services/breadcrumbs.ts @@ -5,7 +5,7 @@ */ import { i18n } from '@kbn/i18n'; import { BASE_PATH } from '../../../common/constants'; -import { ManagementAppMountParams } from '../../../../../../../src/plugins/management/public'; +import { ManagementAppMountParams } from '../../../../../../src/plugins/management/public'; type SetBreadcrumbs = ManagementAppMountParams['setBreadcrumbs']; diff --git a/x-pack/legacy/plugins/index_management/public/application/services/documentation.ts b/x-pack/plugins/index_management/public/application/services/documentation.ts similarity index 98% rename from x-pack/legacy/plugins/index_management/public/application/services/documentation.ts rename to x-pack/plugins/index_management/public/application/services/documentation.ts index e0f261e586b1e..fdf07c43a0c8b 100644 --- a/x-pack/legacy/plugins/index_management/public/application/services/documentation.ts +++ b/x-pack/plugins/index_management/public/application/services/documentation.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { DocLinksStart } from '../../../../../../../src/core/public'; +import { DocLinksStart } from '../../../../../../src/core/public'; import { DataType } from '../components/mappings_editor/types'; import { TYPE_DEFINITION } from '../components/mappings_editor/constants'; diff --git a/x-pack/legacy/plugins/index_management/public/application/services/health_to_color.ts b/x-pack/plugins/index_management/public/application/services/health_to_color.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/services/health_to_color.ts rename to x-pack/plugins/index_management/public/application/services/health_to_color.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/services/http.ts b/x-pack/plugins/index_management/public/application/services/http.ts similarity index 88% rename from x-pack/legacy/plugins/index_management/public/application/services/http.ts rename to x-pack/plugins/index_management/public/application/services/http.ts index a6973c263f00f..931e5fcd21898 100644 --- a/x-pack/legacy/plugins/index_management/public/application/services/http.ts +++ b/x-pack/plugins/index_management/public/application/services/http.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpSetup } from '../../../../../../../src/core/public'; +import { HttpSetup } from '../../../../../../src/core/public'; export class HttpService { private client: any; diff --git a/x-pack/legacy/plugins/index_management/public/application/services/index.ts b/x-pack/plugins/index_management/public/application/services/index.ts similarity index 96% rename from x-pack/legacy/plugins/index_management/public/application/services/index.ts rename to x-pack/plugins/index_management/public/application/services/index.ts index 78ff8cb5c314a..2334d32adf131 100644 --- a/x-pack/legacy/plugins/index_management/public/application/services/index.ts +++ b/x-pack/plugins/index_management/public/application/services/index.ts @@ -21,7 +21,7 @@ export { loadIndexStats, loadIndexMapping, loadIndexData, - loadIndexTemplates, + useLoadIndexTemplates, } from './api'; export { healthToColor } from './health_to_color'; export { sortTable } from './sort_table'; diff --git a/x-pack/legacy/plugins/index_management/public/application/services/navigation.ts b/x-pack/plugins/index_management/public/application/services/navigation.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/services/navigation.ts rename to x-pack/plugins/index_management/public/application/services/navigation.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/services/notification.ts b/x-pack/plugins/index_management/public/application/services/notification.ts similarity index 93% rename from x-pack/legacy/plugins/index_management/public/application/services/notification.ts rename to x-pack/plugins/index_management/public/application/services/notification.ts index 0971ca77c004b..82b9de2272747 100644 --- a/x-pack/legacy/plugins/index_management/public/application/services/notification.ts +++ b/x-pack/plugins/index_management/public/application/services/notification.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { NotificationsStart } from '../../../../../../../src/core/public'; +import { NotificationsStart } from '../../../../../../src/core/public'; export class NotificationService { private _toasts: any; diff --git a/x-pack/legacy/plugins/index_management/public/application/services/routing.ts b/x-pack/plugins/index_management/public/application/services/routing.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/services/routing.ts rename to x-pack/plugins/index_management/public/application/services/routing.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/services/sort_table.ts b/x-pack/plugins/index_management/public/application/services/sort_table.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/services/sort_table.ts rename to x-pack/plugins/index_management/public/application/services/sort_table.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/services/ui_metric.ts b/x-pack/plugins/index_management/public/application/services/ui_metric.ts similarity index 90% rename from x-pack/legacy/plugins/index_management/public/application/services/ui_metric.ts rename to x-pack/plugins/index_management/public/application/services/ui_metric.ts index 7c87ec9509085..73d2ef5aced86 100644 --- a/x-pack/legacy/plugins/index_management/public/application/services/ui_metric.ts +++ b/x-pack/plugins/index_management/public/application/services/ui_metric.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ import { UiStatsMetricType } from '@kbn/analytics'; -import { UsageCollectionSetup } from '../../../../../../../src/plugins/usage_collection/public'; + +import { UsageCollectionSetup } from '../../../../../../src/plugins/usage_collection/public'; import { IndexMgmtMetricsType } from '../../types'; let uiMetricService: UiMetricService; @@ -23,7 +24,8 @@ export class UiMetricService { private track(type: T, name: string) { if (!this.usageCollection) { - throw Error('UiMetricService not initialized.'); + // Usage collection might have been disabled in Kibana config. + return; } this.usageCollection.reportUiStats(this.appName, type as UiStatsMetricType, name); } diff --git a/x-pack/legacy/plugins/index_management/public/application/services/use_request.ts b/x-pack/plugins/index_management/public/application/services/use_request.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/services/use_request.ts rename to x-pack/plugins/index_management/public/application/services/use_request.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/clear_cache_indices.js b/x-pack/plugins/index_management/public/application/store/actions/clear_cache_indices.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/clear_cache_indices.js rename to x-pack/plugins/index_management/public/application/store/actions/clear_cache_indices.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/clear_row_status.js b/x-pack/plugins/index_management/public/application/store/actions/clear_row_status.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/clear_row_status.js rename to x-pack/plugins/index_management/public/application/store/actions/clear_row_status.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/close_indices.js b/x-pack/plugins/index_management/public/application/store/actions/close_indices.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/close_indices.js rename to x-pack/plugins/index_management/public/application/store/actions/close_indices.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/delete_indices.js b/x-pack/plugins/index_management/public/application/store/actions/delete_indices.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/delete_indices.js rename to x-pack/plugins/index_management/public/application/store/actions/delete_indices.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/detail_panel.js b/x-pack/plugins/index_management/public/application/store/actions/detail_panel.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/detail_panel.js rename to x-pack/plugins/index_management/public/application/store/actions/detail_panel.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/edit_index_settings.js b/x-pack/plugins/index_management/public/application/store/actions/edit_index_settings.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/edit_index_settings.js rename to x-pack/plugins/index_management/public/application/store/actions/edit_index_settings.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/extension_action.js b/x-pack/plugins/index_management/public/application/store/actions/extension_action.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/extension_action.js rename to x-pack/plugins/index_management/public/application/store/actions/extension_action.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/flush_indices.js b/x-pack/plugins/index_management/public/application/store/actions/flush_indices.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/flush_indices.js rename to x-pack/plugins/index_management/public/application/store/actions/flush_indices.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/forcemerge_indices.js b/x-pack/plugins/index_management/public/application/store/actions/forcemerge_indices.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/forcemerge_indices.js rename to x-pack/plugins/index_management/public/application/store/actions/forcemerge_indices.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/freeze_indices.js b/x-pack/plugins/index_management/public/application/store/actions/freeze_indices.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/freeze_indices.js rename to x-pack/plugins/index_management/public/application/store/actions/freeze_indices.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/index.js b/x-pack/plugins/index_management/public/application/store/actions/index.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/index.js rename to x-pack/plugins/index_management/public/application/store/actions/index.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/load_index_data.js b/x-pack/plugins/index_management/public/application/store/actions/load_index_data.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/load_index_data.js rename to x-pack/plugins/index_management/public/application/store/actions/load_index_data.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/load_indices.js b/x-pack/plugins/index_management/public/application/store/actions/load_indices.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/load_indices.js rename to x-pack/plugins/index_management/public/application/store/actions/load_indices.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/open_indices.js b/x-pack/plugins/index_management/public/application/store/actions/open_indices.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/open_indices.js rename to x-pack/plugins/index_management/public/application/store/actions/open_indices.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/refresh_indices.js b/x-pack/plugins/index_management/public/application/store/actions/refresh_indices.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/refresh_indices.js rename to x-pack/plugins/index_management/public/application/store/actions/refresh_indices.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/reload_indices.js b/x-pack/plugins/index_management/public/application/store/actions/reload_indices.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/reload_indices.js rename to x-pack/plugins/index_management/public/application/store/actions/reload_indices.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/table_state.js b/x-pack/plugins/index_management/public/application/store/actions/table_state.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/table_state.js rename to x-pack/plugins/index_management/public/application/store/actions/table_state.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/unfreeze_indices.js b/x-pack/plugins/index_management/public/application/store/actions/unfreeze_indices.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/unfreeze_indices.js rename to x-pack/plugins/index_management/public/application/store/actions/unfreeze_indices.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/actions/update_index_settings.js b/x-pack/plugins/index_management/public/application/store/actions/update_index_settings.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/actions/update_index_settings.js rename to x-pack/plugins/index_management/public/application/store/actions/update_index_settings.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/index.ts b/x-pack/plugins/index_management/public/application/store/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/index.ts rename to x-pack/plugins/index_management/public/application/store/index.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/store/reducers/detail_panel.js b/x-pack/plugins/index_management/public/application/store/reducers/detail_panel.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/reducers/detail_panel.js rename to x-pack/plugins/index_management/public/application/store/reducers/detail_panel.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/reducers/index.js b/x-pack/plugins/index_management/public/application/store/reducers/index.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/reducers/index.js rename to x-pack/plugins/index_management/public/application/store/reducers/index.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/reducers/index_management.js b/x-pack/plugins/index_management/public/application/store/reducers/index_management.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/reducers/index_management.js rename to x-pack/plugins/index_management/public/application/store/reducers/index_management.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/reducers/indices.js b/x-pack/plugins/index_management/public/application/store/reducers/indices.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/reducers/indices.js rename to x-pack/plugins/index_management/public/application/store/reducers/indices.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/reducers/row_status.js b/x-pack/plugins/index_management/public/application/store/reducers/row_status.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/reducers/row_status.js rename to x-pack/plugins/index_management/public/application/store/reducers/row_status.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/reducers/table_state.js b/x-pack/plugins/index_management/public/application/store/reducers/table_state.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/reducers/table_state.js rename to x-pack/plugins/index_management/public/application/store/reducers/table_state.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/selectors/index.d.ts b/x-pack/plugins/index_management/public/application/store/selectors/index.d.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/selectors/index.d.ts rename to x-pack/plugins/index_management/public/application/store/selectors/index.d.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/store/selectors/index.js b/x-pack/plugins/index_management/public/application/store/selectors/index.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/selectors/index.js rename to x-pack/plugins/index_management/public/application/store/selectors/index.js diff --git a/x-pack/legacy/plugins/index_management/public/application/store/store.d.ts b/x-pack/plugins/index_management/public/application/store/store.d.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/store.d.ts rename to x-pack/plugins/index_management/public/application/store/store.d.ts diff --git a/x-pack/legacy/plugins/index_management/public/application/store/store.js b/x-pack/plugins/index_management/public/application/store/store.js similarity index 100% rename from x-pack/legacy/plugins/index_management/public/application/store/store.js rename to x-pack/plugins/index_management/public/application/store/store.js diff --git a/x-pack/legacy/plugins/index_management/public/index.scss b/x-pack/plugins/index_management/public/index.scss similarity index 100% rename from x-pack/legacy/plugins/index_management/public/index.scss rename to x-pack/plugins/index_management/public/index.scss diff --git a/x-pack/legacy/plugins/index_management/public/index.ts b/x-pack/plugins/index_management/public/index.ts similarity index 66% rename from x-pack/legacy/plugins/index_management/public/index.ts rename to x-pack/plugins/index_management/public/index.ts index 16e7bf21aee98..6bb921ef648f3 100644 --- a/x-pack/legacy/plugins/index_management/public/index.ts +++ b/x-pack/plugins/index_management/public/index.ts @@ -3,19 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { npSetup } from 'ui/new_platform'; - +import './index.scss'; import { IndexMgmtUIPlugin, IndexMgmtSetup } from './plugin'; /** @public */ -export { IndexMgmtSetup }; - export const plugin = () => { return new IndexMgmtUIPlugin(); }; -// Temp. To be removed after moving to the "plugins" folder - -const { extensionsService } = plugin().setup(npSetup.core, npSetup.plugins); +export { IndexMgmtSetup }; -export { extensionsService }; +export { getIndexListUri } from './application/services/navigation'; diff --git a/x-pack/legacy/plugins/index_management/public/mocks.ts b/x-pack/plugins/index_management/public/mocks.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/mocks.ts rename to x-pack/plugins/index_management/public/mocks.ts diff --git a/x-pack/legacy/plugins/index_management/public/plugin.ts b/x-pack/plugins/index_management/public/plugin.ts similarity index 90% rename from x-pack/legacy/plugins/index_management/public/plugin.ts rename to x-pack/plugins/index_management/public/plugin.ts index 539324766cf95..c1b26fe3ca56b 100644 --- a/x-pack/legacy/plugins/index_management/public/plugin.ts +++ b/x-pack/plugins/index_management/public/plugin.ts @@ -5,10 +5,10 @@ */ import { i18n } from '@kbn/i18n'; -import { CoreSetup } from '../../../../../src/core/public'; -import { UsageCollectionSetup } from '../../../../../src/plugins/usage_collection/public'; -import { ManagementSetup } from '../../../../../src/plugins/management/public'; -import { UIM_APP_NAME } from '../common/constants'; +import { CoreSetup } from '../../../../src/core/public'; +import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/public'; +import { ManagementSetup } from '../../../../src/plugins/management/public'; +import { UIM_APP_NAME, PLUGIN } from '../common/constants'; import { AppDependencies } from './application'; import { httpService } from './application/services/http'; @@ -52,7 +52,7 @@ export class IndexMgmtUIPlugin { this.uiMetricService.setup(usageCollection); management.sections.getSection('elasticsearch')!.registerApp({ - id: 'index_management', + id: PLUGIN.id, title: i18n.translate('xpack.idxMgmt.appTitle', { defaultMessage: 'Index Management' }), order: 1, mount: async ({ element, setBreadcrumbs }) => { diff --git a/x-pack/legacy/plugins/index_management/public/services/extensions_service.mock.ts b/x-pack/plugins/index_management/public/services/extensions_service.mock.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/services/extensions_service.mock.ts rename to x-pack/plugins/index_management/public/services/extensions_service.mock.ts diff --git a/x-pack/legacy/plugins/index_management/public/services/extensions_service.ts b/x-pack/plugins/index_management/public/services/extensions_service.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/services/extensions_service.ts rename to x-pack/plugins/index_management/public/services/extensions_service.ts diff --git a/x-pack/legacy/plugins/index_management/public/services/index.ts b/x-pack/plugins/index_management/public/services/index.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/services/index.ts rename to x-pack/plugins/index_management/public/services/index.ts diff --git a/x-pack/plugins/index_management/public/shared_imports.ts b/x-pack/plugins/index_management/public/shared_imports.ts new file mode 100644 index 0000000000000..cd2964df23d9b --- /dev/null +++ b/x-pack/plugins/index_management/public/shared_imports.ts @@ -0,0 +1,33 @@ +/* + * 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 { + SendRequestConfig, + SendRequestResponse, + UseRequestConfig, + sendRequest, + useRequest, +} from '../../../../src/plugins/es_ui_shared/public/request/np_ready_request'; + +export { + FormSchema, + FIELD_TYPES, + VALIDATION_TYPES, + FieldConfig, + useForm, + Form, + getUseField, +} from '../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib'; + +export { + fieldFormatters, + fieldValidators, + serializers, +} from '../../../../src/plugins/es_ui_shared/static/forms/helpers'; + +export { getFormRow, Field } from '../../../../src/plugins/es_ui_shared/static/forms/components'; + +export { isJSON } from '../../../../src/plugins/es_ui_shared/static/validators/string'; diff --git a/x-pack/legacy/plugins/index_management/public/types.ts b/x-pack/plugins/index_management/public/types.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/public/types.ts rename to x-pack/plugins/index_management/public/types.ts diff --git a/x-pack/legacy/plugins/index_management/public/shared_imports.ts b/x-pack/plugins/index_management/server/config.ts similarity index 52% rename from x-pack/legacy/plugins/index_management/public/shared_imports.ts rename to x-pack/plugins/index_management/server/config.ts index cbc4dde7448ff..5f03575d3ff43 100644 --- a/x-pack/legacy/plugins/index_management/public/shared_imports.ts +++ b/x-pack/plugins/index_management/server/config.ts @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -export { - SendRequestConfig, - SendRequestResponse, - UseRequestConfig, - sendRequest, - useRequest, -} from '../../../../../src/plugins/es_ui_shared/public/request/np_ready_request'; +import { schema, TypeOf } from '@kbn/config-schema'; + +export const configSchema = schema.object({ + enabled: schema.boolean({ defaultValue: true }), +}); + +export type IndexManagementConfig = TypeOf; diff --git a/x-pack/legacy/plugins/index_management/server/index.ts b/x-pack/plugins/index_management/server/index.ts similarity index 67% rename from x-pack/legacy/plugins/index_management/server/index.ts rename to x-pack/plugins/index_management/server/index.ts index 866b374740d3b..e4102711708cb 100644 --- a/x-pack/legacy/plugins/index_management/server/index.ts +++ b/x-pack/plugins/index_management/server/index.ts @@ -5,8 +5,18 @@ */ import { PluginInitializerContext } from 'src/core/server'; + import { IndexMgmtServerPlugin } from './plugin'; +import { configSchema } from './config'; export const plugin = (ctx: PluginInitializerContext) => new IndexMgmtServerPlugin(ctx); +export const config = { + schema: configSchema, +}; + +/** @public */ export { Dependencies } from './types'; +export { IndexMgmtSetup } from './plugin'; +export { Index } from './types'; +export { IndexManagementConfig } from './config'; diff --git a/x-pack/legacy/plugins/index_management/server/lib/fetch_aliases.test.ts b/x-pack/plugins/index_management/server/lib/fetch_aliases.test.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/server/lib/fetch_aliases.test.ts rename to x-pack/plugins/index_management/server/lib/fetch_aliases.test.ts diff --git a/x-pack/legacy/plugins/index_management/server/lib/fetch_aliases.ts b/x-pack/plugins/index_management/server/lib/fetch_aliases.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/server/lib/fetch_aliases.ts rename to x-pack/plugins/index_management/server/lib/fetch_aliases.ts diff --git a/x-pack/legacy/plugins/index_management/server/lib/fetch_indices.ts b/x-pack/plugins/index_management/server/lib/fetch_indices.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/server/lib/fetch_indices.ts rename to x-pack/plugins/index_management/server/lib/fetch_indices.ts diff --git a/x-pack/legacy/plugins/index_management/server/lib/get_managed_templates.ts b/x-pack/plugins/index_management/server/lib/get_managed_templates.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/server/lib/get_managed_templates.ts rename to x-pack/plugins/index_management/server/lib/get_managed_templates.ts diff --git a/x-pack/legacy/plugins/index_management/server/lib/is_es_error.ts b/x-pack/plugins/index_management/server/lib/is_es_error.ts similarity index 100% rename from x-pack/legacy/plugins/index_management/server/lib/is_es_error.ts rename to x-pack/plugins/index_management/server/lib/is_es_error.ts diff --git a/x-pack/legacy/plugins/index_management/server/plugin.ts b/x-pack/plugins/index_management/server/plugin.ts similarity index 94% rename from x-pack/legacy/plugins/index_management/server/plugin.ts rename to x-pack/plugins/index_management/server/plugin.ts index 95d27e1cf16ba..a0a9151cdb71f 100644 --- a/x-pack/legacy/plugins/index_management/server/plugin.ts +++ b/x-pack/plugins/index_management/server/plugin.ts @@ -24,8 +24,8 @@ export class IndexMgmtServerPlugin implements Plugin Date: Tue, 25 Feb 2020 09:05:22 +0100 Subject: [PATCH 039/123] [SIEM] Upgrades cypress to version 4.0.2 (#58400) * upgrades cypress to version 4.0.2 * fixes failing tests --- .../timeline_search_or_filter.spec.ts | 5 +- .../cypress/integration/url_state.spec.ts | 5 +- .../cypress/tasks/hosts/authentications.ts | 4 + .../cypress/tasks/hosts/uncommon_processes.ts | 4 + .../plugins/siem/cypress/tasks/timeline.ts | 5 +- .../components/fields_browser/header.test.tsx | 2 - x-pack/package.json | 2 +- yarn.lock | 301 ++++++++---------- 8 files changed, 159 insertions(+), 169 deletions(-) diff --git a/x-pack/legacy/plugins/siem/cypress/integration/timeline_search_or_filter.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/timeline_search_or_filter.spec.ts index c06fd69a558a4..f738ff792049a 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/timeline_search_or_filter.spec.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/timeline_search_or_filter.spec.ts @@ -24,6 +24,9 @@ describe('timeline search or filter KQL bar', () => { cy.get(SERVER_SIDE_EVENT_COUNT) .invoke('text') - .should('be.above', 0); + .then(strCount => { + const intCount = +strCount; + cy.wrap(intCount).should('be.above', 0); + }); }); }); diff --git a/x-pack/legacy/plugins/siem/cypress/integration/url_state.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/url_state.spec.ts index cabdb98fa5b67..11c0562eb3638 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/url_state.spec.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/url_state.spec.ts @@ -236,7 +236,10 @@ describe('url state', () => { cy.get(SERVER_SIDE_EVENT_COUNT) .invoke('text') - .should('be.above', 0); + .then(strCount => { + const intCount = +strCount; + cy.wrap(intCount).should('be.above', 0); + }); const bestTimelineName = 'The Best Timeline'; addNameToTimeline(bestTimelineName); diff --git a/x-pack/legacy/plugins/siem/cypress/tasks/hosts/authentications.ts b/x-pack/legacy/plugins/siem/cypress/tasks/hosts/authentications.ts index f5f15150e8ac3..ce3767a340376 100644 --- a/x-pack/legacy/plugins/siem/cypress/tasks/hosts/authentications.ts +++ b/x-pack/legacy/plugins/siem/cypress/tasks/hosts/authentications.ts @@ -5,7 +5,11 @@ */ import { AUTHENTICATIONS_TABLE } from '../../screens/hosts/authentications'; +import { REFRESH_BUTTON } from '../../screens/siem_header'; export const waitForAuthenticationsToBeLoaded = () => { cy.get(AUTHENTICATIONS_TABLE).should('exist'); + cy.get(REFRESH_BUTTON) + .invoke('text') + .should('not.equal', 'Updating'); }; diff --git a/x-pack/legacy/plugins/siem/cypress/tasks/hosts/uncommon_processes.ts b/x-pack/legacy/plugins/siem/cypress/tasks/hosts/uncommon_processes.ts index c44249acdd964..a28a7df07c3f8 100644 --- a/x-pack/legacy/plugins/siem/cypress/tasks/hosts/uncommon_processes.ts +++ b/x-pack/legacy/plugins/siem/cypress/tasks/hosts/uncommon_processes.ts @@ -5,7 +5,11 @@ */ import { UNCOMMON_PROCESSES_TABLE } from '../../screens/hosts/uncommon_processes'; +import { REFRESH_BUTTON } from '../../screens/siem_header'; export const waitForUncommonProcessesToBeLoaded = () => { cy.get(UNCOMMON_PROCESSES_TABLE).should('exist'); + cy.get(REFRESH_BUTTON) + .invoke('text') + .should('not.equal', 'Updating'); }; diff --git a/x-pack/legacy/plugins/siem/cypress/tasks/timeline.ts b/x-pack/legacy/plugins/siem/cypress/tasks/timeline.ts index 76acdad990a7e..c218d5153356b 100644 --- a/x-pack/legacy/plugins/siem/cypress/tasks/timeline.ts +++ b/x-pack/legacy/plugins/siem/cypress/tasks/timeline.ts @@ -65,7 +65,10 @@ export const populateTimeline = () => { executeTimelineKQL(hostExistsQuery); cy.get(SERVER_SIDE_EVENT_COUNT) .invoke('text') - .should('be.above', 0); + .then(strCount => { + const intCount = +strCount; + cy.wrap(intCount).should('be.above', 0); + }); }; export const uncheckTimestampToggleField = () => { diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/header.test.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/header.test.tsx index 42689065354d0..2abc2fd1046e0 100644 --- a/x-pack/legacy/plugins/siem/public/components/fields_browser/header.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/header.test.tsx @@ -6,11 +6,9 @@ import { mount } from 'enzyme'; import React from 'react'; - import { mockBrowserFields } from '../../containers/source/mock'; import { TestProviders } from '../../mock'; import { defaultHeaders } from '../timeline/body/column_headers/default_headers'; - import { Header } from './header'; const timelineId = 'test'; diff --git a/x-pack/package.json b/x-pack/package.json index 551e466893f93..f76b0182ea228 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -117,7 +117,7 @@ "cheerio": "0.22.0", "commander": "3.0.2", "copy-webpack-plugin": "^5.0.4", - "cypress": "^3.6.1", + "cypress": "^4.0.2", "cypress-multi-reporters": "^1.2.3", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.2", diff --git a/yarn.lock b/yarn.lock index 8ea23c17b8b8b..f46e869909e2e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7023,13 +7023,6 @@ async@2.4.0: dependencies: lodash "^4.14.0" -async@2.6.1, async@^2.6.0, async@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" - integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== - dependencies: - lodash "^4.17.10" - async@^2.0.0, async@^2.1.4: version "2.6.0" resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" @@ -7037,6 +7030,13 @@ async@^2.0.0, async@^2.1.4: dependencies: lodash "^4.14.0" +async@^2.6.0, async@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== + dependencies: + lodash "^4.17.10" + async@^2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" @@ -7044,6 +7044,11 @@ async@^2.6.3: dependencies: lodash "^4.17.14" +async@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" + integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== + async@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" @@ -7909,6 +7914,11 @@ bluebird@3.5.5, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.5: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== +bluebird@3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + bluebird@^3.3.0, bluebird@^3.3.1: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" @@ -8536,12 +8546,10 @@ cacheable-request@^2.1.1: normalize-url "2.0.1" responselike "1.0.2" -cachedir@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-1.3.0.tgz#5e01928bf2d95b5edd94b0942188246740e0dbc4" - integrity sha512-O1ji32oyON9laVPJL1IZ5bmwd2cB46VfpxkDequezH+15FDzzVddEyrGEeX4WusDSqKxdyFdDQDEG1yo1GoWkg== - dependencies: - os-homedir "^1.0.1" +cachedir@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" + integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw== caching-transform@^3.0.2: version "3.0.2" @@ -8806,6 +8814,14 @@ chalk@2.4.2, chalk@^2.3.2, chalk@^2.4.2, chalk@~2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@3.0.0, chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -8835,14 +8851,6 @@ chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^5.2.0" -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" @@ -9087,11 +9095,6 @@ ci-info@^1.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.2.tgz#03561259db48d0474c8bdc90f5b47b068b6bbfb4" integrity sha512-uTGIPNx/nSpBdsF6xnseRXLLtfr9VLqkz8ZqHXr3Y7b6SftyRxBGjwMtJj1OhNbmlc1wZzLNAlAcvyIiE8a6ZA== -ci-info@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" - integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== - ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -9596,11 +9599,6 @@ commander@2, commander@2.19.0, commander@^2.11.0, commander@^2.12.2: resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== -commander@2.15.1: - version "2.15.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" - integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== - commander@2.17.x, commander@~2.17.1: version "2.17.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" @@ -9611,6 +9609,11 @@ commander@3.0.2: resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== +commander@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.0.tgz#545983a0603fe425bc672d66c9e3c89c42121a83" + integrity sha512-NIQrwvv9V39FHgGFm36+U9SMQzbiHvU79k+iADraJTpmrFFfx7Ds0IvDoAdZsDrknlkRk14OYoWXb57uTh7/sw== + commander@^2.13.0, commander@^2.15.1, commander@^2.16.0, commander@^2.19.0: version "2.20.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" @@ -10646,41 +10649,42 @@ cypress-multi-reporters@^1.2.3: debug "^4.1.1" lodash "^4.17.11" -cypress@^3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.6.1.tgz#4420957923879f60b7a5146ccbf81841a149b653" - integrity sha512-6n0oqENdz/oQ7EJ6IgESNb2M7Bo/70qX9jSJsAziJTC3kICfEMmJUlrAnP9bn+ut24MlXQST5nRXhUP5nRIx6A== +cypress@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-4.0.2.tgz#ede194d7bc73fb449f8de553c9e1db4ca15309ef" + integrity sha512-WRzxOoSd+TxyXKa7Zi9orz3ii5VW7yhhVYstCU+EpOKfPan9x5Ww2Clucmy4H/W0GHUYAo7GYFZRD33ZCSNBQA== dependencies: "@cypress/listr-verbose-renderer" "0.4.1" "@cypress/xvfb" "1.2.4" "@types/sizzle" "2.3.2" arch "2.1.1" - bluebird "3.5.0" - cachedir "1.3.0" - chalk "2.4.2" + bluebird "3.7.2" + cachedir "2.3.0" + chalk "3.0.0" check-more-types "2.24.0" - commander "2.15.1" + commander "4.1.0" common-tags "1.8.0" - debug "3.2.6" - execa "0.10.0" + debug "4.1.1" + eventemitter2 "4.1.2" + execa "3.3.0" executable "4.1.1" extract-zip "1.6.7" - fs-extra "5.0.0" - getos "3.1.1" - is-ci "1.2.1" + fs-extra "8.1.0" + getos "3.1.4" + is-ci "2.0.0" is-installed-globally "0.1.0" lazy-ass "1.6.0" - listr "0.12.0" + listr "0.14.3" lodash "4.17.15" - log-symbols "2.2.0" + log-symbols "3.0.0" minimist "1.2.0" moment "2.24.0" - ramda "0.24.1" + ramda "0.26.1" request "2.88.0" request-progress "3.0.0" - supports-color "5.5.0" + supports-color "7.1.0" tmp "0.1.0" - untildify "3.0.3" + untildify "4.0.0" url "0.11.0" yauzl "2.10.0" @@ -11065,7 +11069,7 @@ debug@4.1.0: dependencies: ms "^2.1.1" -debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: +debug@4.1.1, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -13028,6 +13032,11 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +eventemitter2@4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-4.1.2.tgz#0e1a8477af821a6ef3995b311bf74c23a5247f15" + integrity sha1-DhqEd6+CGm7zmVsxG/dMI6UkfxU= + eventemitter2@~0.4.13: version "0.4.14" resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" @@ -13078,19 +13087,6 @@ exec-sh@^0.3.2: resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.2.tgz#6738de2eb7c8e671d0366aea0b0db8c6f7d7391b" integrity sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg== -execa@0.10.0, execa@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" - integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== - dependencies: - cross-spawn "^6.0.0" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - execa@1.0.0, execa@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -13104,6 +13100,22 @@ execa@1.0.0, execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +execa@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-3.3.0.tgz#7e348eef129a1937f21ecbbd53390942653522c1" + integrity sha512-j5Vit5WZR/cbHlqU97+qcnw9WHRCIL4V1SVe75VcHcD1JRBdt8fv0zw89b7CQHQdUHTt2VjuhcF5ibAgVOxqpg== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + p-finally "^2.0.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + execa@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-0.1.1.tgz#b09c2a9309bc0ef0501479472db3180f8d4c3edd" @@ -13113,6 +13125,19 @@ execa@^0.1.1: object-assign "^4.0.1" strip-eof "^1.0.0" +execa@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== + dependencies: + cross-spawn "^6.0.0" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + execa@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.4.0.tgz#4eb6467a36a095fabb2970ff9d5e3fb7bce6ebc3" @@ -14321,12 +14346,12 @@ fs-exists-sync@^0.1.0: resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0= -fs-extra@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" - integrity sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ== +fs-extra@8.1.0, fs-extra@^8.0.1: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== dependencies: - graceful-fs "^4.1.2" + graceful-fs "^4.2.0" jsonfile "^4.0.0" universalify "^0.1.0" @@ -14368,15 +14393,6 @@ fs-extra@^7.0.0, fs-extra@^7.0.1, fs-extra@~7.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^8.0.1: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" @@ -14703,12 +14719,12 @@ getopts@^2.2.5: resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.5.tgz#67a0fe471cacb9c687d817cab6450b96dde8313b" integrity sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA== -getos@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/getos/-/getos-3.1.1.tgz#967a813cceafee0156b0483f7cffa5b3eff029c5" - integrity sha512-oUP1rnEhAr97rkitiszGP9EgDVYnmchgFzfqRzSkgtfv7ai6tEi7Ko8GgjNXts7VLWEqrTWyhsOKLe5C5b/Zkg== +getos@3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/getos/-/getos-3.1.4.tgz#29cdf240ed10a70c049add7b6f8cb08c81876faf" + integrity sha512-UORPzguEB/7UG5hqiZai8f0vQ7hzynMQyJLxStoQ8dPGAcmgsfXOPA4iE/fGtweHYkK+z4zc9V0g+CIFRf5HYw== dependencies: - async "2.6.1" + async "^3.1.0" getos@^3.1.0: version "3.1.0" @@ -17152,12 +17168,12 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.1.5: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== -is-ci@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" - integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== +is-ci@2.0.0, is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== dependencies: - ci-info "^1.5.0" + ci-info "^2.0.0" is-ci@^1.0.10: version "1.1.0" @@ -17166,13 +17182,6 @@ is-ci@^1.0.10: dependencies: ci-info "^1.0.0" -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -19254,20 +19263,6 @@ listr-update-renderer@0.5.0, listr-update-renderer@^0.5.0: log-update "^2.3.0" strip-ansi "^3.0.1" -listr-update-renderer@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.2.0.tgz#ca80e1779b4e70266807e8eed1ad6abe398550f9" - integrity sha1-yoDhd5tOcCZoB+ju0a1qvjmFUPk= - dependencies: - chalk "^1.1.3" - cli-truncate "^0.2.1" - elegant-spinner "^1.0.1" - figures "^1.7.0" - indent-string "^3.0.0" - log-symbols "^1.0.2" - log-update "^1.0.2" - strip-ansi "^3.0.1" - listr-update-renderer@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz#344d980da2ca2e8b145ba305908f32ae3f4cc8a7" @@ -19302,28 +19297,6 @@ listr-verbose-renderer@^0.5.0: date-fns "^1.27.2" figures "^2.0.0" -listr@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/listr/-/listr-0.12.0.tgz#6bce2c0f5603fa49580ea17cd6a00cc0e5fa451a" - integrity sha1-a84sD1YD+klYDqF81qAMwOX6RRo= - dependencies: - chalk "^1.1.3" - cli-truncate "^0.2.1" - figures "^1.7.0" - indent-string "^2.1.0" - is-promise "^2.1.0" - is-stream "^1.1.0" - listr-silent-renderer "^1.1.1" - listr-update-renderer "^0.2.0" - listr-verbose-renderer "^0.4.0" - log-symbols "^1.0.2" - log-update "^1.0.2" - ora "^0.2.3" - p-map "^1.1.1" - rxjs "^5.0.0-beta.11" - stream-to-observable "^0.1.0" - strip-ansi "^3.0.1" - listr@0.14.3: version "0.14.3" resolved "https://registry.yarnpkg.com/listr/-/listr-0.14.3.tgz#2fea909604e434be464c50bddba0d496928fa586" @@ -19824,6 +19797,13 @@ log-symbols@2.2.0, log-symbols@^2.0.0, log-symbols@^2.1.0, log-symbols@^2.2.0: dependencies: chalk "^2.0.1" +log-symbols@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" + integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== + dependencies: + chalk "^2.4.2" + log-symbols@^1.0.1, log-symbols@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" @@ -23983,21 +23963,16 @@ railroad-diagrams@^1.0.0: resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" integrity sha1-635iZ1SN3t+4mcG5Dlc3RVnN234= -ramda@0.24.1: - version "0.24.1" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.24.1.tgz#c3b7755197f35b8dc3502228262c4c91ddb6b857" - integrity sha1-w7d1UZfzW43DUCIoJixMkd22uFc= +ramda@0.26.1, ramda@^0.26, ramda@^0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06" + integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ== ramda@^0.21.0: version "0.21.0" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35" integrity sha1-oAGr7bP/YQd9T/HVd9RN536NCjU= -ramda@^0.26, ramda@^0.26.1: - version "0.26.1" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06" - integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ== - randexp@0.4.6: version "0.4.6" resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3" @@ -26375,7 +26350,7 @@ rxjs@6.5.2: dependencies: tslib "^1.9.0" -rxjs@^5.0.0-beta.11, rxjs@^5.5.2: +rxjs@^5.5.2: version "5.5.12" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.12.tgz#6fa61b8a77c3d793dbaf270bee2f43f652d741cc" integrity sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw== @@ -27815,11 +27790,6 @@ stream-spigot@~2.1.2: dependencies: readable-stream "~1.1.0" -stream-to-observable@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.1.0.tgz#45bf1d9f2d7dc09bed81f1c307c430e68b84cffe" - integrity sha1-Rb8dny19wJvtgfHDB8Qw5ouEz/4= - streamroller@0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-0.7.0.tgz#a1d1b7cf83d39afb0d63049a5acbf93493bdf64b" @@ -28291,13 +28261,6 @@ supertest@^3.1.0: methods "~1.1.2" superagent "3.8.2" -supports-color@5.5.0, supports-color@^5.0.0, supports-color@^5.4.0, supports-color@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - supports-color@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" @@ -28312,6 +28275,13 @@ supports-color@6.1.0, supports-color@^6.0.0, supports-color@^6.1.0: dependencies: has-flag "^3.0.0" +supports-color@7.1.0, supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" + supports-color@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" @@ -28329,6 +28299,13 @@ supports-color@^3.1.0, supports-color@^3.1.2, supports-color@^3.2.3: dependencies: has-flag "^1.0.0" +supports-color@^5.0.0, supports-color@^5.4.0, supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + supports-color@^5.2.0, supports-color@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" @@ -28343,13 +28320,6 @@ supports-color@^7.0.0: dependencies: has-flag "^4.0.0" -supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== - dependencies: - has-flag "^4.0.0" - supports-hyperlinks@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz#71daedf36cc1060ac5100c351bb3da48c29c0ef7" @@ -30241,10 +30211,10 @@ unstated@^2.1.1: dependencies: create-react-context "^0.1.5" -untildify@3.0.3, untildify@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9" - integrity sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA== +untildify@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== untildify@^2.0.0: version "2.1.0" @@ -30253,6 +30223,11 @@ untildify@^2.0.0: dependencies: os-homedir "^1.0.0" +untildify@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9" + integrity sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA== + unzip-response@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe" From a60b25f9ad45cbc8efb5f362d30996c0d49baa2b Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Tue, 25 Feb 2020 09:05:53 +0100 Subject: [PATCH 040/123] fix short url in spaces (#58313) --- src/plugins/share/server/routes/goto.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/plugins/share/server/routes/goto.ts b/src/plugins/share/server/routes/goto.ts index 5c3a4e441099f..0c5b74915e58a 100644 --- a/src/plugins/share/server/routes/goto.ts +++ b/src/plugins/share/server/routes/goto.ts @@ -23,6 +23,7 @@ import { schema } from '@kbn/config-schema'; import { shortUrlAssertValid } from './lib/short_url_assert_valid'; import { ShortUrlLookupService } from './lib/short_url_lookup'; import { getGotoPath } from '../../common/short_url_routes'; +import { modifyUrl } from '../../../../core/utils'; export const createGotoRoute = ({ router, @@ -49,9 +50,16 @@ export const createGotoRoute = ({ const uiSettings = context.core.uiSettings.client; const stateStoreInSessionStorage = await uiSettings.get('state:storeInSessionStorage'); if (!stateStoreInSessionStorage) { + const basePath = http.basePath.get(request); + + const prependedUrl = modifyUrl(url, parts => { + if (!parts.hostname && parts.pathname && parts.pathname.startsWith('/')) { + parts.pathname = `${basePath}${parts.pathname}`; + } + }); return response.redirected({ headers: { - location: http.basePath.prepend(url), + location: prependedUrl, }, }); } From 1a96ff3c302c08ea049245a05c716ecd43ca0485 Mon Sep 17 00:00:00 2001 From: Robert Oskamp Date: Tue, 25 Feb 2020 11:00:10 +0100 Subject: [PATCH 041/123] [ML] Functional tests - stabilize typing during df analytics creation (#58227) This PR makes the typing in data frame analytics tests more robust. --- .../data_frame_analytics_creation.ts | 24 ++++++++++++------- x-pack/test/functional/services/ml.ts | 5 +++- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/x-pack/test/functional/services/machine_learning/data_frame_analytics_creation.ts b/x-pack/test/functional/services/machine_learning/data_frame_analytics_creation.ts index b4e455ebaa63f..96dc8993c3d35 100644 --- a/x-pack/test/functional/services/machine_learning/data_frame_analytics_creation.ts +++ b/x-pack/test/functional/services/machine_learning/data_frame_analytics_creation.ts @@ -6,10 +6,12 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; +import { MlCommon } from './common'; -export function MachineLearningDataFrameAnalyticsCreationProvider({ - getService, -}: FtrProviderContext) { +export function MachineLearningDataFrameAnalyticsCreationProvider( + { getService }: FtrProviderContext, + mlCommon: MlCommon +) { const testSubjects = getService('testSubjects'); const comboBox = getService('comboBox'); const retry = getService('retry'); @@ -85,14 +87,14 @@ export function MachineLearningDataFrameAnalyticsCreationProvider({ }, async setJobId(jobId: string) { - await testSubjects.setValue('mlAnalyticsCreateJobFlyoutJobIdInput', jobId, { + await mlCommon.setValueWithChecks('mlAnalyticsCreateJobFlyoutJobIdInput', jobId, { clearWithKeyboard: true, }); await this.assertJobIdValue(jobId); }, async setJobDescription(jobDescription: string) { - await testSubjects.setValue('mlDFAnalyticsJobCreationJobDescription', jobDescription, { + await mlCommon.setValueWithChecks('mlDFAnalyticsJobCreationJobDescription', jobDescription, { clearWithKeyboard: true, }); await this.assertJobDescriptionValue(jobDescription); @@ -136,9 +138,13 @@ export function MachineLearningDataFrameAnalyticsCreationProvider({ }, async setDestIndex(destIndex: string) { - await testSubjects.setValue('mlAnalyticsCreateJobFlyoutDestinationIndexInput', destIndex, { - clearWithKeyboard: true, - }); + await mlCommon.setValueWithChecks( + 'mlAnalyticsCreateJobFlyoutDestinationIndexInput', + destIndex, + { + clearWithKeyboard: true, + } + ); await this.assertDestIndexValue(destIndex); }, @@ -248,7 +254,7 @@ export function MachineLearningDataFrameAnalyticsCreationProvider({ }, async setModelMemory(modelMemory: string) { - await testSubjects.setValue('mlAnalyticsCreateJobFlyoutModelMemoryInput', modelMemory, { + await mlCommon.setValueWithChecks('mlAnalyticsCreateJobFlyoutModelMemoryInput', modelMemory, { clearWithKeyboard: true, }); await this.assertModelMemoryValue(modelMemory); diff --git a/x-pack/test/functional/services/ml.ts b/x-pack/test/functional/services/ml.ts index 2660a90662dec..354e0907375ca 100644 --- a/x-pack/test/functional/services/ml.ts +++ b/x-pack/test/functional/services/ml.ts @@ -42,7 +42,10 @@ export function MachineLearningProvider(context: FtrProviderContext) { const api = MachineLearningAPIProvider(context); const customUrls = MachineLearningCustomUrlsProvider(context); const dataFrameAnalytics = MachineLearningDataFrameAnalyticsProvider(context, api); - const dataFrameAnalyticsCreation = MachineLearningDataFrameAnalyticsCreationProvider(context); + const dataFrameAnalyticsCreation = MachineLearningDataFrameAnalyticsCreationProvider( + context, + common + ); const dataFrameAnalyticsTable = MachineLearningDataFrameAnalyticsTableProvider(context); const dataVisualizer = MachineLearningDataVisualizerProvider(context); const dataVisualizerIndexBased = MachineLearningDataVisualizerIndexBasedProvider(context); From 737205fb9b0c5b27ff06331598802a2e57365ffb Mon Sep 17 00:00:00 2001 From: Maryia Lapata Date: Tue, 25 Feb 2020 13:19:02 +0300 Subject: [PATCH 042/123] Move src/legacy/ui/public/notify/app_redirect to kibana_legacy (#58127) Co-authored-by: Elastic Machine --- .../core_plugins/kibana/public/kibana.js | 6 ++-- src/legacy/ui/public/notify/index.js | 1 - .../notify/app_redirect/app_redirect.test.ts} | 32 +++++++++++-------- .../notify/app_redirect/app_redirect.ts} | 9 +++--- .../public/notify/app_redirect/index.ts} | 0 .../kibana_legacy/public/notify/index.ts | 1 + .../dashboard_mode/public/dashboard_viewer.js | 6 ++-- .../plugins/graph/public/application.ts | 2 +- .../plugins/graph/public/legacy_imports.ts | 2 -- 9 files changed, 33 insertions(+), 26 deletions(-) rename src/{legacy/ui/public/notify/app_redirect/app_redirect.test.js => plugins/kibana_legacy/public/notify/app_redirect/app_redirect.test.ts} (75%) rename src/{legacy/ui/public/notify/app_redirect/app_redirect.js => plugins/kibana_legacy/public/notify/app_redirect/app_redirect.ts} (82%) rename src/{legacy/ui/public/notify/app_redirect/index.js => plugins/kibana_legacy/public/notify/app_redirect/index.ts} (100%) diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js index d77fc780f4cc2..384c6bd80ec33 100644 --- a/src/legacy/core_plugins/kibana/public/kibana.js +++ b/src/legacy/core_plugins/kibana/public/kibana.js @@ -53,7 +53,7 @@ import './management'; import './dev_tools'; import 'ui/agg_response'; import 'ui/agg_types'; -import { showAppRedirectNotification } from 'ui/notify'; +import { showAppRedirectNotification } from '../../../../plugins/kibana_legacy/public'; import 'leaflet'; import { localApplicationService } from './local_application_service'; @@ -68,4 +68,6 @@ routes.otherwise({ redirectTo: `/${config.defaultAppId || 'discover'}`, }); -uiModules.get('kibana').run(showAppRedirectNotification); +uiModules + .get('kibana') + .run($location => showAppRedirectNotification($location, npSetup.core.notifications.toasts)); diff --git a/src/legacy/ui/public/notify/index.js b/src/legacy/ui/public/notify/index.js index f7526f3b8f8fd..7ec6a394d7e88 100644 --- a/src/legacy/ui/public/notify/index.js +++ b/src/legacy/ui/public/notify/index.js @@ -19,5 +19,4 @@ export { fatalError, addFatalErrorCallback } from './fatal_error'; export { toastNotifications } from './toasts'; -export { addAppRedirectMessageToUrl, showAppRedirectNotification } from './app_redirect'; export { banners } from './banners'; diff --git a/src/legacy/ui/public/notify/app_redirect/app_redirect.test.js b/src/plugins/kibana_legacy/public/notify/app_redirect/app_redirect.test.ts similarity index 75% rename from src/legacy/ui/public/notify/app_redirect/app_redirect.test.js rename to src/plugins/kibana_legacy/public/notify/app_redirect/app_redirect.test.ts index a23aabe6ad88e..efb1393ff0b16 100644 --- a/src/legacy/ui/public/notify/app_redirect/app_redirect.test.js +++ b/src/plugins/kibana_legacy/public/notify/app_redirect/app_redirect.test.ts @@ -17,17 +17,12 @@ * under the License. */ +import { ILocationService } from 'angular'; +import { ToastsStart } from '../../../../../core/public'; import { addAppRedirectMessageToUrl, showAppRedirectNotification } from './app_redirect'; let isToastAdded = false; - -jest.mock('../toasts', () => ({ - toastNotifications: { - addDanger: () => { - isToastAdded = true; - }, - }, -})); +const toasts: ToastsStart = {} as ToastsStart; describe('addAppRedirectMessageToUrl', () => { test('adds a message to the URL', () => { @@ -39,20 +34,29 @@ describe('addAppRedirectMessageToUrl', () => { describe('showAppRedirectNotification', () => { beforeEach(() => { isToastAdded = false; + toasts.addDanger = (): any => { + isToastAdded = true; + }; }); test(`adds a toast when there's a message in the URL`, () => { - showAppRedirectNotification({ - search: () => ({ app_redirect_message: 'redirect message' }), - }); + showAppRedirectNotification( + { + search: () => ({ app_redirect_message: 'redirect message' }), + } as ILocationService, + toasts + ); expect(isToastAdded).toBe(true); }); test(`doesn't add a toast when there's no message in the URL`, () => { - showAppRedirectNotification({ - search: () => ({ app_redirect_message: '' }), - }); + showAppRedirectNotification( + { + search: () => ({ app_redirect_message: '' }), + } as ILocationService, + toasts + ); expect(isToastAdded).toBe(false); }); diff --git a/src/legacy/ui/public/notify/app_redirect/app_redirect.js b/src/plugins/kibana_legacy/public/notify/app_redirect/app_redirect.ts similarity index 82% rename from src/legacy/ui/public/notify/app_redirect/app_redirect.js rename to src/plugins/kibana_legacy/public/notify/app_redirect/app_redirect.ts index a92e5401e5e75..e79ab4b2fbc6d 100644 --- a/src/legacy/ui/public/notify/app_redirect/app_redirect.js +++ b/src/plugins/kibana_legacy/public/notify/app_redirect/app_redirect.ts @@ -17,12 +17,13 @@ * under the License. */ +import { ILocationService } from 'angular'; import { modifyUrl } from '../../../../../core/utils'; -import { toastNotifications } from '../toasts'; +import { ToastsStart } from '../../../../../core/public'; const APP_REDIRECT_MESSAGE_PARAM = 'app_redirect_message'; -export function addAppRedirectMessageToUrl(url, message) { +export function addAppRedirectMessageToUrl(url: string, message: string) { return modifyUrl(url, urlParts => { urlParts.hash = modifyUrl(urlParts.hash || '', hashParts => { hashParts.query[APP_REDIRECT_MESSAGE_PARAM] = message; @@ -32,7 +33,7 @@ export function addAppRedirectMessageToUrl(url, message) { // If an app needs to redirect, e.g. due to an expired license, it can surface a message via // the URL query params. -export function showAppRedirectNotification($location) { +export function showAppRedirectNotification($location: ILocationService, toasts: ToastsStart) { const queryString = $location.search(); if (!queryString[APP_REDIRECT_MESSAGE_PARAM]) { @@ -42,5 +43,5 @@ export function showAppRedirectNotification($location) { const message = queryString[APP_REDIRECT_MESSAGE_PARAM]; $location.search(APP_REDIRECT_MESSAGE_PARAM, null); - toastNotifications.addDanger(message); + toasts.addDanger(message); } diff --git a/src/legacy/ui/public/notify/app_redirect/index.js b/src/plugins/kibana_legacy/public/notify/app_redirect/index.ts similarity index 100% rename from src/legacy/ui/public/notify/app_redirect/index.js rename to src/plugins/kibana_legacy/public/notify/app_redirect/index.ts diff --git a/src/plugins/kibana_legacy/public/notify/index.ts b/src/plugins/kibana_legacy/public/notify/index.ts index 6aa4e36ab7227..b6f29876c2737 100644 --- a/src/plugins/kibana_legacy/public/notify/index.ts +++ b/src/plugins/kibana_legacy/public/notify/index.ts @@ -18,3 +18,4 @@ */ export * from './toasts'; export * from './lib'; +export { addAppRedirectMessageToUrl, showAppRedirectNotification } from './app_redirect'; diff --git a/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js b/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js index 8ca023aa90cf1..e0e49fe59daf4 100644 --- a/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js +++ b/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js @@ -37,7 +37,7 @@ import 'plugins/kibana/dashboard/legacy'; import { npStart } from 'ui/new_platform'; import { localApplicationService } from 'plugins/kibana/local_application_service'; -import { showAppRedirectNotification } from 'ui/notify'; +import { showAppRedirectNotification } from '../../../../../src/plugins/kibana_legacy/public'; import { DashboardConstants, createDashboardEditUrl } from 'plugins/kibana/dashboard'; npStart.plugins.kibanaLegacy.dashboardConfig.turnHideWriteControlsOn(); @@ -51,7 +51,9 @@ chrome.setRootController('kibana', function() { npStart.core.chrome.navLinks.showOnly('kibana:dashboard'); }); -uiModules.get('kibana').run(showAppRedirectNotification); +uiModules + .get('kibana') + .run($location => showAppRedirectNotification($location, npStart.core.notifications.toasts)); /** * If there is a configured `kibana.defaultAppId`, and it is a dashboard ID, we'll diff --git a/x-pack/legacy/plugins/graph/public/application.ts b/x-pack/legacy/plugins/graph/public/application.ts index 80a797b7f0724..7bd18f841b478 100644 --- a/x-pack/legacy/plugins/graph/public/application.ts +++ b/x-pack/legacy/plugins/graph/public/application.ts @@ -24,7 +24,6 @@ import { configureAppAngularModule, createTopNavDirective, createTopNavHelper, - addAppRedirectMessageToUrl, } from './legacy_imports'; // @ts-ignore import { initGraphApp } from './app'; @@ -37,6 +36,7 @@ import { checkLicense } from '../../../../plugins/graph/common/check_license'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../src/plugins/navigation/public'; import { createSavedWorkspacesLoader } from './services/persistence/saved_workspace_loader'; import { Storage } from '../../../../../src/plugins/kibana_utils/public'; +import { addAppRedirectMessageToUrl } from '../../../../../src/plugins/kibana_legacy/public'; /** * These are dependencies of the Graph app besides the base dependencies diff --git a/x-pack/legacy/plugins/graph/public/legacy_imports.ts b/x-pack/legacy/plugins/graph/public/legacy_imports.ts index ac518d34551db..84fafdb580abe 100644 --- a/x-pack/legacy/plugins/graph/public/legacy_imports.ts +++ b/x-pack/legacy/plugins/graph/public/legacy_imports.ts @@ -8,6 +8,4 @@ import 'ace'; // @ts-ignore export { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav'; -// @ts-ignore -export { addAppRedirectMessageToUrl } from 'ui/notify'; export { configureAppAngularModule } from '../../../../../src/plugins/kibana_legacy/public'; From 5910e83722ae3c211731f9671e6ceee438d75aca Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Tue, 25 Feb 2020 11:27:25 +0100 Subject: [PATCH 043/123] hide welcome screen for cloud (#58371) --- x-pack/test/functional/page_objects/security_page.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/x-pack/test/functional/page_objects/security_page.js b/x-pack/test/functional/page_objects/security_page.js index 3bcba7cbd1696..5889a374e443e 100644 --- a/x-pack/test/functional/page_objects/security_page.js +++ b/x-pack/test/functional/page_objects/security_page.js @@ -30,6 +30,11 @@ export function SecurityPageProvider({ getService, getPageObjects }) { const rawDataTabLocator = 'a[id=rawdata-tab]'; await PageObjects.common.navigateToApp('login'); + + // ensure welcome screen won't be shown. This is relevant for environments which don't allow + // to use the yml setting, e.g. cloud + await browser.setLocalStorageItem('home:welcome:show', 'false'); + await testSubjects.setValue('loginUsername', username); await testSubjects.setValue('loginPassword', password); await testSubjects.click('loginSubmit'); From 506268c926d18f27133d93f419c0b594eca609aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20Haro?= Date: Tue, 25 Feb 2020 10:31:35 +0000 Subject: [PATCH 044/123] [Telemetry] Separate the license retrieval from the stats in the usage collectors (#57332) * [Telemetry] Merge OSS and XPack usage collectors * Create X-Pack collector again * Separate the license retrieval from the stats * Fix telemetry tests with new fields * Use Promise.all to retrieve license and stats at the same time * Fix moment mock Co-authored-by: Elastic Machine --- .../telemetry/server/collection_manager.ts | 56 +- ...et_cluster_info.js => get_cluster_info.ts} | 24 +- .../telemetry_collection/get_local_license.ts | 90 ++ .../telemetry_collection/get_local_stats.ts | 26 +- .../server/telemetry_collection/index.ts | 1 - .../register_collection.ts | 2 + .../public/services/telemetry_service.test.ts | 10 + .../public/services/telemetry_service.ts | 5 +- .../get_all_stats.test.ts | 12 +- .../telemetry_collection/get_all_stats.ts | 41 +- .../telemetry_collection/get_es_stats.ts | 11 +- .../telemetry_collection/get_licenses.test.ts | 84 ++ .../telemetry_collection/get_licenses.ts | 84 ++ .../register_monitoring_collection.ts | 2 + .../get_stats_with_xpack.test.ts.snap | 118 ++ .../__tests__/get_xpack.js | 105 +- .../server/telemetry_collection/constants.ts | 1 + .../get_stats_with_xpack.test.ts | 113 ++ .../get_stats_with_xpack.ts | 28 +- .../server/telemetry_collection/get_xpack.js | 85 -- .../server/telemetry_collection/get_xpack.ts | 25 + .../register_xpack_collection.ts | 2 + .../apis/telemetry/fixtures/basiccluster.json | 7 + .../apis/telemetry/fixtures/multicluster.json | 1002 ++++++++++++++++- 24 files changed, 1671 insertions(+), 263 deletions(-) rename src/legacy/core_plugins/telemetry/server/telemetry_collection/{get_cluster_info.js => get_cluster_info.ts} (61%) create mode 100644 src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_license.ts create mode 100644 x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_licenses.test.ts create mode 100644 x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_licenses.ts create mode 100644 x-pack/legacy/plugins/xpack_main/server/telemetry_collection/__snapshots__/get_stats_with_xpack.test.ts.snap create mode 100644 x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_stats_with_xpack.test.ts delete mode 100644 x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_xpack.js create mode 100644 x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_xpack.ts diff --git a/src/legacy/core_plugins/telemetry/server/collection_manager.ts b/src/legacy/core_plugins/telemetry/server/collection_manager.ts index 0394dea343adf..715ca56e290a2 100644 --- a/src/legacy/core_plugins/telemetry/server/collection_manager.ts +++ b/src/legacy/core_plugins/telemetry/server/collection_manager.ts @@ -20,6 +20,7 @@ import { encryptTelemetry } from './collectors'; import { CallCluster } from '../../elasticsearch'; import { UsageCollectionSetup } from '../../../../plugins/usage_collection/server'; +import { ESLicense } from './telemetry_collection/get_local_license'; export type EncryptedStatsGetterConfig = { unencrypted: false } & { server: any; @@ -45,22 +46,38 @@ export interface StatsCollectionConfig { end: string | number; } +export interface BasicStatsPayload { + timestamp: string; + cluster_uuid: string; + cluster_name: string; + version: string; + cluster_stats: object; + collection?: string; + stack_stats: object; +} + export type StatsGetterConfig = UnencryptedStatsGetterConfig | EncryptedStatsGetterConfig; export type ClusterDetailsGetter = (config: StatsCollectionConfig) => Promise; -export type StatsGetter = ( +export type StatsGetter = ( + clustersDetails: ClusterDetails[], + config: StatsCollectionConfig +) => Promise; +export type LicenseGetter = ( clustersDetails: ClusterDetails[], config: StatsCollectionConfig -) => Promise; +) => Promise<{ [clusterUuid: string]: ESLicense | undefined }>; -interface CollectionConfig { +interface CollectionConfig { title: string; priority: number; esCluster: string; - statsGetter: StatsGetter; + statsGetter: StatsGetter; clusterDetailsGetter: ClusterDetailsGetter; + licenseGetter: LicenseGetter; } interface Collection { statsGetter: StatsGetter; + licenseGetter: LicenseGetter; clusterDetailsGetter: ClusterDetailsGetter; esCluster: string; title: string; @@ -70,8 +87,15 @@ export class TelemetryCollectionManager { private usageGetterMethodPriority = -1; private collections: Collection[] = []; - public setCollection = (collectionConfig: CollectionConfig) => { - const { title, priority, esCluster, statsGetter, clusterDetailsGetter } = collectionConfig; + public setCollection = (collectionConfig: CollectionConfig) => { + const { + title, + priority, + esCluster, + statsGetter, + clusterDetailsGetter, + licenseGetter, + } = collectionConfig; if (typeof priority !== 'number') { throw new Error('priority must be set.'); @@ -88,10 +112,14 @@ export class TelemetryCollectionManager { throw Error('esCluster name must be set for the getCluster method.'); } if (!clusterDetailsGetter) { - throw Error('Cluser UUIds method is not set.'); + throw Error('Cluster UUIds method is not set.'); + } + if (!licenseGetter) { + throw Error('License getter method not set.'); } this.collections.unshift({ + licenseGetter, statsGetter, clusterDetailsGetter, esCluster, @@ -141,7 +169,19 @@ export class TelemetryCollectionManager { return; } - return await collection.statsGetter(clustersDetails, statsCollectionConfig); + const [stats, licenses] = await Promise.all([ + collection.statsGetter(clustersDetails, statsCollectionConfig), + collection.licenseGetter(clustersDetails, statsCollectionConfig), + ]); + + return stats.map(stat => { + const license = licenses[stat.cluster_uuid]; + return { + ...(license ? { license } : {}), + ...stat, + collectionSource: collection.title, + }; + }); }; public getOptInStats = async (optInStatus: boolean, config: StatsGetterConfig) => { diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_cluster_info.js b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_cluster_info.ts similarity index 61% rename from src/legacy/core_plugins/telemetry/server/telemetry_collection/get_cluster_info.js rename to src/legacy/core_plugins/telemetry/server/telemetry_collection/get_cluster_info.ts index 2e4ed0b36ed26..67812457ed4ec 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_cluster_info.js +++ b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_cluster_info.ts @@ -17,14 +17,32 @@ * under the License. */ +import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; + +// This can be removed when the ES client improves the types +export interface ESClusterInfo { + cluster_uuid: string; + cluster_name: string; + version: { + number: string; + build_flavor: string; + build_type: string; + build_hash: string; + build_date: string; + build_snapshot?: boolean; + lucene_version: string; + minimum_wire_compatibility_version: string; + minimum_index_compatibility_version: string; + }; +} + /** * Get the cluster info from the connected cluster. * * This is the equivalent to GET / * * @param {function} callCluster The callWithInternalUser handler (exposed for testing) - * @return {Promise} The response from Elasticsearch. */ -export function getClusterInfo(callCluster) { - return callCluster('info'); +export function getClusterInfo(callCluster: CallCluster) { + return callCluster('info'); } diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_license.ts b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_license.ts new file mode 100644 index 0000000000000..589392ffb6095 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_license.ts @@ -0,0 +1,90 @@ +/* + * 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 { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; +import { LicenseGetter } from '../collection_manager'; + +// From https://www.elastic.co/guide/en/elasticsearch/reference/current/get-license.html +export interface ESLicense { + status: string; + uid: string; + type: string; + issue_date: string; + issue_date_in_millis: number; + expiry_date: string; + expirty_date_in_millis: number; + max_nodes: number; + issued_to: string; + issuer: string; + start_date_in_millis: number; +} +let cachedLicense: ESLicense | undefined; + +function fetchLicense(callCluster: CallCluster, local: boolean) { + return callCluster<{ license: ESLicense }>('transport.request', { + method: 'GET', + path: '/_license', + query: { + local, + // For versions >= 7.6 and < 8.0, this flag is needed otherwise 'platinum' is returned for 'enterprise' license. + accept_enterprise: 'true', + }, + }); +} + +/** + * Get the cluster's license from the connected node. + * + * This is the equivalent of GET /_license?local=true . + * + * Like any X-Pack related API, X-Pack must installed for this to work. + */ +async function getLicenseFromLocalOrMaster(callCluster: CallCluster) { + // Fetching the local license is cheaper than getting it from the master and good enough + const { license } = await fetchLicense(callCluster, true).catch(async err => { + if (cachedLicense) { + try { + // Fallback to the master node's license info + const response = await fetchLicense(callCluster, false); + return response; + } catch (masterError) { + if (masterError.statusCode === 404) { + // If the master node does not have a license, we can assume there is no license + cachedLicense = undefined; + } else { + // Any other errors from the master node, throw and do not send any telemetry + throw err; + } + } + } + return { license: void 0 }; + }); + + if (license) { + cachedLicense = license; + } + return license; +} + +export const getLocalLicense: LicenseGetter = async (clustersDetails, { callCluster }) => { + const license = await getLicenseFromLocalOrMaster(callCluster); + + // It should be called only with 1 cluster element in the clustersDetails array, but doing reduce just in case. + return clustersDetails.reduce((acc, { clusterUuid }) => ({ ...acc, [clusterUuid]: license }), {}); +}; diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats.ts b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats.ts index 8adb6d237bee8..d99710deb1cbc 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats.ts +++ b/src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats.ts @@ -17,11 +17,8 @@ * under the License. */ -import { get, omit } from 'lodash'; -// @ts-ignore -import { getClusterInfo } from './get_cluster_info'; +import { getClusterInfo, ESClusterInfo } from './get_cluster_info'; import { getClusterStats } from './get_cluster_stats'; -// @ts-ignore import { getKibana, handleKibanaStats, KibanaUsageStats } from './get_kibana'; import { StatsGetter } from '../collection_manager'; @@ -33,20 +30,19 @@ import { StatsGetter } from '../collection_manager'; * @param {Object} clusterInfo Cluster info (GET /) * @param {Object} clusterStats Cluster stats (GET /_cluster/stats) * @param {Object} kibana The Kibana Usage stats - * @return {Object} A combined object containing the different responses. */ export function handleLocalStats( server: any, - clusterInfo: any, - clusterStats: any, + { cluster_name, cluster_uuid, version }: ESClusterInfo, + { _nodes, cluster_name: clusterName, ...clusterStats }: any, kibana: KibanaUsageStats ) { return { timestamp: new Date().toISOString(), - cluster_uuid: get(clusterInfo, 'cluster_uuid'), - cluster_name: get(clusterInfo, 'cluster_name'), - version: get(clusterInfo, 'version.number'), - cluster_stats: omit(clusterStats, '_nodes', 'cluster_name'), + cluster_uuid, + cluster_name, + version: version.number, + cluster_stats: clusterStats, collection: 'local', stack_stats: { kibana: handleKibanaStats(server, kibana), @@ -54,14 +50,12 @@ export function handleLocalStats( }; } +export type TelemetryLocalStats = ReturnType; + /** * Get statistics for all products joined by Elasticsearch cluster. - * - * @param {Object} server The Kibana server instance used to call ES as the internal user - * @param {function} callCluster The callWithInternalUser handler (exposed for testing) - * @return {Promise} The object containing the current Elasticsearch cluster's telemetry. */ -export const getLocalStats: StatsGetter = async (clustersDetails, config) => { +export const getLocalStats: StatsGetter = async (clustersDetails, config) => { const { server, callCluster, usageCollection } = config; return await Promise.all( diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_collection/index.ts b/src/legacy/core_plugins/telemetry/server/telemetry_collection/index.ts index 7f228dbc5e6f6..9ac94216c21bc 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_collection/index.ts +++ b/src/legacy/core_plugins/telemetry/server/telemetry_collection/index.ts @@ -17,7 +17,6 @@ * under the License. */ -// @ts-ignore export { getLocalStats } from './get_local_stats'; export { getClusterUuids } from './get_cluster_stats'; export { registerCollection } from './register_collection'; diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_collection/register_collection.ts b/src/legacy/core_plugins/telemetry/server/telemetry_collection/register_collection.ts index faf8e9de79194..6580b47dba08e 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_collection/register_collection.ts +++ b/src/legacy/core_plugins/telemetry/server/telemetry_collection/register_collection.ts @@ -39,6 +39,7 @@ import { telemetryCollectionManager } from '../collection_manager'; import { getLocalStats } from './get_local_stats'; import { getClusterUuids } from './get_cluster_stats'; +import { getLocalLicense } from './get_local_license'; export function registerCollection() { telemetryCollectionManager.setCollection({ @@ -47,5 +48,6 @@ export function registerCollection() { priority: 0, statsGetter: getLocalStats, clusterDetailsGetter: getClusterUuids, + licenseGetter: getLocalLicense, }); } diff --git a/src/plugins/telemetry/public/services/telemetry_service.test.ts b/src/plugins/telemetry/public/services/telemetry_service.test.ts index 0ebcd52f1423c..0a49b0ae3084e 100644 --- a/src/plugins/telemetry/public/services/telemetry_service.test.ts +++ b/src/plugins/telemetry/public/services/telemetry_service.test.ts @@ -26,9 +26,18 @@ const mockSubtract = jest.fn().mockImplementation(() => { }; }); +const mockClone = jest.fn().mockImplementation(() => { + return { + clone: mockClone, + subtract: mockSubtract, + toISOString: jest.fn(), + }; +}); + jest.mock('moment', () => { return jest.fn().mockImplementation(() => { return { + clone: mockClone, subtract: mockSubtract, toISOString: jest.fn(), }; @@ -43,6 +52,7 @@ describe('TelemetryService', () => { expect(telemetryService['http'].post).toBeCalledWith('/api/telemetry/v2/clusters/_stats', { body: JSON.stringify({ unencrypted: false, timeRange: {} }), }); + expect(mockClone).toBeCalled(); expect(mockSubtract).toBeCalledWith(20, 'minutes'); }); }); diff --git a/src/plugins/telemetry/public/services/telemetry_service.ts b/src/plugins/telemetry/public/services/telemetry_service.ts index 073886e7d1327..cb91451bd8ef4 100644 --- a/src/plugins/telemetry/public/services/telemetry_service.ts +++ b/src/plugins/telemetry/public/services/telemetry_service.ts @@ -92,7 +92,10 @@ export class TelemetryService { body: JSON.stringify({ unencrypted, timeRange: { - min: now.subtract(20, 'minutes').toISOString(), + min: now + .clone() // Need to clone it to avoid mutation (and max being the same value) + .subtract(20, 'minutes') + .toISOString(), max: now.toISOString(), }, }), diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts index 470642f9dd8a3..dcc7924fe171a 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts @@ -5,7 +5,7 @@ */ import sinon from 'sinon'; -import { addStackStats, getAllStats, handleAllStats } from './get_all_stats'; +import { getStackStats, getAllStats, handleAllStats } from './get_all_stats'; import { ESClusterStats } from './get_es_stats'; import { KibanaStats } from './get_kibana_stats'; import { ClustersHighLevelStats } from './get_high_level_stats'; @@ -223,7 +223,8 @@ describe('get_all_stats', () => { beats: {}, }); - expect(clusters).toStrictEqual(expectedClusters); + const [a, b, c] = expectedClusters; + expect(clusters).toStrictEqual([a, b, { ...c, stack_stats: {} }]); }); it('handles no clusters response', () => { @@ -233,9 +234,8 @@ describe('get_all_stats', () => { }); }); - describe('addStackStats', () => { + describe('getStackStats', () => { it('searches for clusters', () => { - const cluster = { cluster_uuid: 'a' }; const stats = { a: { count: 2, @@ -250,9 +250,7 @@ describe('get_all_stats', () => { }, }; - addStackStats(cluster as ESClusterStats, stats, 'xyz'); - - expect((cluster as any).stack_stats.xyz).toStrictEqual(stats.a); + expect(getStackStats('a', stats, 'xyz')).toStrictEqual({ xyz: stats.a }); }); }); }); diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.ts b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.ts index aa5e937387daf..a6ed5254dabd5 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.ts +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.ts @@ -61,38 +61,31 @@ export function handleAllStats( } ) { return clusters.map(cluster => { - // if they are using Kibana or Logstash, then add it to the cluster details under cluster.stack_stats - addStackStats(cluster, kibana, KIBANA_SYSTEM_ID); - addStackStats(cluster, logstash, LOGSTASH_SYSTEM_ID); - addStackStats(cluster, beats, BEATS_SYSTEM_ID); - mergeXPackStats(cluster, kibana, 'graph_workspace', 'graph'); // copy graph_workspace info out of kibana, merge it into stack_stats.xpack.graph + const stats = { + ...cluster, + stack_stats: { + ...cluster.stack_stats, + // if they are using Kibana or Logstash, then add it to the cluster details under cluster.stack_stats + ...getStackStats(cluster.cluster_uuid, kibana, KIBANA_SYSTEM_ID), + ...getStackStats(cluster.cluster_uuid, logstash, LOGSTASH_SYSTEM_ID), + ...getStackStats(cluster.cluster_uuid, beats, BEATS_SYSTEM_ID), + }, + }; - return cluster; + mergeXPackStats(stats, kibana, 'graph_workspace', 'graph'); // copy graph_workspace info out of kibana, merge it into stack_stats.xpack.graph + + return stats; }); } -/** - * Add product data to the {@code cluster}, only if it exists for the current {@code cluster}. - * - * @param {Object} cluster The current Elasticsearch cluster stats - * @param {Object} allProductStats Product stats, keyed by Cluster UUID - * @param {String} product The product name being added (e.g., 'kibana' or 'logstash') - */ -export function addStackStats( - cluster: ESClusterStats & { stack_stats?: { [product: string]: K } }, +export function getStackStats( + clusterUuid: string, allProductStats: T, product: string ) { - const productStats = allProductStats[cluster.cluster_uuid]; - + const productStats = allProductStats[clusterUuid]; // Don't add it if they're not using (or configured to report stats) this product for this cluster - if (productStats) { - if (!cluster.stack_stats) { - cluster.stack_stats = {}; - } - - cluster.stack_stats[product] = productStats; - } + return productStats ? { [product]: productStats } : {}; } export function mergeXPackStats( diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.ts b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.ts index f0ae1163d3f52..2f2fffd3f0823 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.ts +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.ts @@ -48,11 +48,6 @@ export function fetchElasticsearchStats( 'hits.hits._source.timestamp', 'hits.hits._source.cluster_name', 'hits.hits._source.version', - 'hits.hits._source.license.status', // license data only includes necessary fields to drive UI - 'hits.hits._source.license.type', - 'hits.hits._source.license.issue_date', - 'hits.hits._source.license.expiry_date', - 'hits.hits._source.license.expiry_date_in_millis', 'hits.hits._source.cluster_stats', 'hits.hits._source.stack_stats', ], @@ -79,7 +74,11 @@ export function fetchElasticsearchStats( export interface ESClusterStats { cluster_uuid: string; - type: 'cluster_stats'; + cluster_name: string; + timestamp: string; + version: string; + cluster_stats: object; + stack_stats?: object; } /** diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_licenses.test.ts b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_licenses.test.ts new file mode 100644 index 0000000000000..bb8326ce0b63a --- /dev/null +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_licenses.test.ts @@ -0,0 +1,84 @@ +/* + * 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 sinon from 'sinon'; +import { getLicenses, handleLicenses, fetchLicenses } from './get_licenses'; + +describe('get_licenses', () => { + const callWith = sinon.stub(); + const size = 123; + const server = { + config: sinon.stub().returns({ + get: sinon + .stub() + .withArgs('xpack.monitoring.elasticsearch.index_pattern') + .returns('.monitoring-es-N-*') + .withArgs('xpack.monitoring.max_bucket_size') + .returns(size), + }), + }; + const response = { + hits: { + hits: [ + { _id: 'abc', _source: { cluster_uuid: 'abc', license: { type: 'basic' } } }, + { _id: 'xyz', _source: { cluster_uuid: 'xyz', license: { type: 'basic' } } }, + { _id: '123', _source: { cluster_uuid: '123' } }, + ], + }, + }; + const expectedClusters = response.hits.hits.map(hit => hit._source); + const clusterUuids = expectedClusters.map(cluster => ({ clusterUuid: cluster.cluster_uuid })); + const expectedLicenses = { + abc: { type: 'basic' }, + xyz: { type: 'basic' }, + '123': void 0, + }; + + describe('getLicenses', () => { + it('returns clusters', async () => { + callWith.withArgs('search').returns(Promise.resolve(response)); + + expect( + await getLicenses(clusterUuids, { server, callCluster: callWith } as any) + ).toStrictEqual(expectedLicenses); + }); + }); + + describe('fetchLicenses', () => { + it('searches for clusters', async () => { + callWith.returns(response); + + expect( + await fetchLicenses( + server, + callWith, + clusterUuids.map(({ clusterUuid }) => clusterUuid) + ) + ).toStrictEqual(response); + }); + }); + + describe('handleLicenses', () => { + // filterPath makes it easy to ignore anything unexpected because it will come back empty + it('handles unexpected response', () => { + const clusters = handleLicenses({} as any); + + expect(clusters).toStrictEqual({}); + }); + + it('handles valid response', () => { + const clusters = handleLicenses(response as any); + + expect(clusters).toStrictEqual(expectedLicenses); + }); + + it('handles no hits response', () => { + const clusters = handleLicenses({ hits: { hits: [] } } as any); + + expect(clusters).toStrictEqual({}); + }); + }); +}); diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_licenses.ts b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_licenses.ts new file mode 100644 index 0000000000000..7364227e7dc92 --- /dev/null +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_licenses.ts @@ -0,0 +1,84 @@ +/* + * 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 { + StatsCollectionConfig, + LicenseGetter, +} from 'src/legacy/core_plugins/telemetry/server/collection_manager'; +import { SearchResponse } from 'elasticsearch'; +import { ESLicense } from 'src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_license'; +import { INDEX_PATTERN_ELASTICSEARCH } from '../../common/constants'; + +/** + * Get statistics for all selected Elasticsearch clusters. + */ +export const getLicenses: LicenseGetter = async (clustersDetails, { server, callCluster }) => { + const clusterUuids = clustersDetails.map(({ clusterUuid }) => clusterUuid); + const response = await fetchLicenses(server, callCluster, clusterUuids); + return handleLicenses(response); +}; + +/** + * Fetch the Elasticsearch stats. + * + * @param {Object} server The server instance + * @param {function} callCluster The callWithRequest or callWithInternalUser handler + * @param {Array} clusterUuids Cluster UUIDs to limit the request against + * + * Returns the response for the aggregations to fetch details for the product. + */ +export function fetchLicenses( + server: StatsCollectionConfig['server'], + callCluster: StatsCollectionConfig['callCluster'], + clusterUuids: string[] +) { + const config = server.config(); + const params = { + index: INDEX_PATTERN_ELASTICSEARCH, + size: config.get('monitoring.ui.max_bucket_size'), + ignoreUnavailable: true, + filterPath: ['hits.hits._source.cluster_uuid', 'hits.hits._source.license'], + body: { + query: { + bool: { + filter: [ + /* + * Note: Unlike most places, we don't care about the old _type: cluster_stats because it would NOT + * have the license in it (that used to be in the .monitoring-data-2 index in cluster_info) + */ + { term: { type: 'cluster_stats' } }, + { terms: { cluster_uuid: clusterUuids } }, + ], + }, + }, + collapse: { field: 'cluster_uuid' }, + sort: { timestamp: { order: 'desc' } }, + }, + }; + + return callCluster('search', params); +} + +export interface ESClusterStatsWithLicense { + cluster_uuid: string; + type: 'cluster_stats'; + license?: ESLicense; +} + +/** + * Extract the cluster stats for each cluster. + */ +export function handleLicenses(response: SearchResponse) { + const clusters = response.hits?.hits || []; + + return clusters.reduce( + (acc, { _source }) => ({ + ...acc, + [_source.cluster_uuid]: _source.license, + }), + {} + ); +} diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts index f0fda5229cb5c..0b14eb05f796f 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts +++ b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts @@ -7,6 +7,7 @@ import { telemetryCollectionManager } from '../../../../../../src/legacy/core_plugins/telemetry/server'; import { getAllStats } from './get_all_stats'; import { getClusterUuids } from './get_cluster_uuids'; +import { getLicenses } from './get_licenses'; export function registerMonitoringCollection() { telemetryCollectionManager.setCollection({ @@ -15,5 +16,6 @@ export function registerMonitoringCollection() { priority: 2, statsGetter: getAllStats, clusterDetailsGetter: getClusterUuids, + licenseGetter: getLicenses, }); } diff --git a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/__snapshots__/get_stats_with_xpack.test.ts.snap b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/__snapshots__/get_stats_with_xpack.test.ts.snap new file mode 100644 index 0000000000000..1a70504dc9391 --- /dev/null +++ b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/__snapshots__/get_stats_with_xpack.test.ts.snap @@ -0,0 +1,118 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Telemetry Collection: Get Aggregated Stats OSS-like telemetry (no license nor X-Pack telemetry) 1`] = ` +Array [ + Object { + "cluster_name": "test", + "cluster_stats": Object {}, + "cluster_uuid": "test", + "collection": "local", + "stack_stats": Object { + "kibana": Object { + "count": 1, + "great": "googlymoogly", + "indices": 1, + "os": Object { + "platformReleases": Array [ + Object { + "count": 1, + "platformRelease": "iv", + }, + ], + "platforms": Array [ + Object { + "count": 1, + "platform": "rocky", + }, + ], + }, + "plugins": Object { + "clouds": Object { + "chances": 95, + }, + "localization": Object { + "integrities": Object {}, + "labelsCount": 0, + "locale": "en", + }, + "rain": Object { + "chances": 2, + }, + "snow": Object { + "chances": 0, + }, + "sun": Object { + "chances": 5, + }, + }, + "versions": Array [ + Object { + "count": 1, + "version": "8675309", + }, + ], + }, + }, + "version": "8.0.0", + }, +] +`; + +exports[`Telemetry Collection: Get Aggregated Stats X-Pack telemetry (license + X-Pack) 1`] = ` +Array [ + Object { + "cluster_name": "test", + "cluster_stats": Object {}, + "cluster_uuid": "test", + "collection": "local", + "stack_stats": Object { + "kibana": Object { + "count": 1, + "great": "googlymoogly", + "indices": 1, + "os": Object { + "platformReleases": Array [ + Object { + "count": 1, + "platformRelease": "iv", + }, + ], + "platforms": Array [ + Object { + "count": 1, + "platform": "rocky", + }, + ], + }, + "plugins": Object { + "clouds": Object { + "chances": 95, + }, + "localization": Object { + "integrities": Object {}, + "labelsCount": 0, + "locale": "en", + }, + "rain": Object { + "chances": 2, + }, + "snow": Object { + "chances": 0, + }, + "sun": Object { + "chances": 5, + }, + }, + "versions": Array [ + Object { + "count": 1, + "version": "8675309", + }, + ], + }, + "xpack": Object {}, + }, + "version": "8.0.0", + }, +] +`; diff --git a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/__tests__/get_xpack.js b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/__tests__/get_xpack.js index eca130b4d7465..eb03701fd195b 100644 --- a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/__tests__/get_xpack.js +++ b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/__tests__/get_xpack.js @@ -8,42 +8,7 @@ import expect from '@kbn/expect'; import sinon from 'sinon'; import { TIMEOUT } from '../constants'; -import { getXPackLicense, getXPackUsage, getXPack, handleXPack } from '../get_xpack'; - -function mockGetXPackLicense(callCluster, license, req) { - callCluster - .withArgs(req, 'transport.request', { - method: 'GET', - path: '/_license', - query: { - local: 'true', - accept_enterprise: 'true', - }, - }) - .returns( - license.then( - response => ({ license: response }), - () => {} // Catch error so that we don't emit UnhandledPromiseRejectionWarning for tests with invalid license - ) - ); - - callCluster - .withArgs('transport.request', { - method: 'GET', - path: '/_license', - query: { - local: 'true', - accept_enterprise: 'true', - }, - }) - // conveniently wraps the passed in license object as { license: response }, like it really is - .returns( - license.then( - response => ({ license: response }), - () => {} // Catch error so that we don't emit UnhandledPromiseRejectionWarning for tests with invalid license - ) - ); -} +import { getXPackUsage } from '../get_xpack'; function mockGetXPackUsage(callCluster, usage, req) { callCluster @@ -67,31 +32,7 @@ function mockGetXPackUsage(callCluster, usage, req) { .returns(usage); } -/** - * Mock getXPack responses. - * - * @param {Function} callCluster Sinon function mock. - * @param {Promise} license Promised license response. - * @param {Promise} usage Promised usage response. - * @param {Object} usage reqeust object. - */ -export function mockGetXPack(callCluster, license, usage, req) { - mockGetXPackLicense(callCluster, license, req); - mockGetXPackUsage(callCluster, usage, req); -} - describe('get_xpack', () => { - describe('getXPackLicense', () => { - it('uses callCluster to get /_license API', async () => { - const response = { type: 'basic' }; - const callCluster = sinon.stub(); - - mockGetXPackLicense(callCluster, Promise.resolve(response)); - - expect(await getXPackLicense(callCluster)).to.eql(response); - }); - }); - describe('getXPackUsage', () => { it('uses callCluster to get /_xpack/usage API', () => { const response = Promise.resolve({}); @@ -102,48 +43,4 @@ describe('get_xpack', () => { expect(getXPackUsage(callCluster)).to.be(response); }); }); - - describe('handleXPack', () => { - it('uses data as expected', () => { - const license = { fake: 'data' }; - const usage = { also: 'fake', nested: { object: { data: [{ field: 1 }, { field: 2 }] } } }; - - expect(handleXPack(license, usage)).to.eql({ license, stack_stats: { xpack: usage } }); - }); - }); - - describe('getXPack', () => { - it('returns the formatted response object', async () => { - const license = { fancy: 'license' }; - const xpack = { also: 'fancy' }; - - const callCluster = sinon.stub(); - - mockGetXPack(callCluster, Promise.resolve(license), Promise.resolve(xpack)); - - const data = await getXPack(callCluster); - - expect(data).to.eql({ license, xpack }); - }); - - it('returns empty object upon license failure', async () => { - const callCluster = sinon.stub(); - - mockGetXPack(callCluster, Promise.reject(new Error()), Promise.resolve({ also: 'fancy' })); - - const data = await getXPack(callCluster); - - expect(data).to.eql({}); - }); - - it('returns empty object upon usage failure', async () => { - const callCluster = sinon.stub(); - - mockGetXPack(callCluster, Promise.resolve({ fancy: 'license' }), Promise.reject(new Error())); - - const data = await getXPack(callCluster); - - expect(data).to.eql({}); - }); - }); }); diff --git a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/constants.ts b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/constants.ts index c89fbe416a0cc..b6f1aabab95c4 100644 --- a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/constants.ts +++ b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/constants.ts @@ -7,4 +7,5 @@ /** * The timeout used by each request, whenever a timeout can be specified. */ + export const TIMEOUT = '30s'; diff --git a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_stats_with_xpack.test.ts b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_stats_with_xpack.test.ts new file mode 100644 index 0000000000000..b85cbd9661022 --- /dev/null +++ b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_stats_with_xpack.test.ts @@ -0,0 +1,113 @@ +/* + * 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 { getStatsWithXpack } from './get_stats_with_xpack'; + +const kibana = { + kibana: { + great: 'googlymoogly', + versions: [{ version: '8675309', count: 1 }], + }, + kibana_stats: { + os: { + platform: 'rocky', + platformRelease: 'iv', + }, + }, + localization: { + locale: 'en', + labelsCount: 0, + integrities: {}, + }, + sun: { chances: 5 }, + clouds: { chances: 95 }, + rain: { chances: 2 }, + snow: { chances: 0 }, +}; + +const getMockServer = (getCluster = jest.fn()) => ({ + log(tags: string[], message: string) { + // eslint-disable-next-line no-console + console.log({ tags, message }); + }, + config() { + return { + get(item: string) { + switch (item) { + case 'pkg.version': + return '8675309-snapshot'; + default: + throw Error(`unexpected config.get('${item}') received.`); + } + }, + }; + }, + plugins: { + elasticsearch: { getCluster }, + }, +}); + +const mockUsageCollection = (kibanaUsage = kibana) => ({ + bulkFetch: () => kibanaUsage, + toObject: (data: any) => data, +}); + +describe('Telemetry Collection: Get Aggregated Stats', () => { + test('OSS-like telemetry (no license nor X-Pack telemetry)', async () => { + const callCluster = jest.fn(async (method: string, options: { path?: string }) => { + switch (method) { + case 'transport.request': + if (options.path === '/_license' || options.path === '/_xpack/usage') { + // eslint-disable-next-line no-throw-literal + throw { statusCode: 404 }; + } + return {}; + case 'info': + return { cluster_uuid: 'test', cluster_name: 'test', version: { number: '8.0.0' } }; + default: + return {}; + } + }); + const usageCollection = mockUsageCollection(); + const server = getMockServer(); + + const stats = await getStatsWithXpack([{ clusterUuid: '1234' }], { + callCluster, + usageCollection, + server, + } as any); + expect(stats.map(({ timestamp, ...rest }) => rest)).toMatchSnapshot(); + }); + + test('X-Pack telemetry (license + X-Pack)', async () => { + const callCluster = jest.fn(async (method: string, options: { path?: string }) => { + switch (method) { + case 'transport.request': + if (options.path === '/_license') { + return { + license: { type: 'basic' }, + }; + } + if (options.path === '/_xpack/usage') { + return {}; + } + case 'info': + return { cluster_uuid: 'test', cluster_name: 'test', version: { number: '8.0.0' } }; + default: + return {}; + } + }); + const usageCollection = mockUsageCollection(); + const server = getMockServer(); + + const stats = await getStatsWithXpack([{ clusterUuid: '1234' }], { + callCluster, + usageCollection, + server, + } as any); + expect(stats.map(({ timestamp, ...rest }) => rest)).toMatchSnapshot(); + }); +}); diff --git a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_stats_with_xpack.ts b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_stats_with_xpack.ts index 41076d96231c9..ea7465f66f120 100644 --- a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_stats_with_xpack.ts +++ b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_stats_with_xpack.ts @@ -4,19 +4,33 @@ * you may not use this file except in compliance with the Elastic License. */ -// @ts-ignore -import { getXPack } from './get_xpack'; -import { getLocalStats } from '../../../../../../src/legacy/core_plugins/telemetry/server/telemetry_collection'; import { StatsGetter } from '../../../../../../src/legacy/core_plugins/telemetry/server/collection_manager'; +import { + getLocalStats, + TelemetryLocalStats, +} from '../../../../../../src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_stats'; +import { getXPackUsage } from './get_xpack'; -export const getStatsWithXpack: StatsGetter = async function(clustersDetails, config) { +export type TelemetryAggregatedStats = TelemetryLocalStats & { + stack_stats: { xpack?: object }; +}; + +export const getStatsWithXpack: StatsGetter = async function( + clustersDetails, + config +) { const { callCluster } = config; const clustersLocalStats = await getLocalStats(clustersDetails, config); - const { license, xpack } = await getXPack(callCluster); + const xpack = await getXPackUsage(callCluster).catch(() => undefined); // We want to still report something (and do not lose the license) even when this method fails. return clustersLocalStats.map(localStats => { - localStats.license = license; - localStats.stack_stats.xpack = xpack; + if (xpack) { + return { + ...localStats, + stack_stats: { ...localStats.stack_stats, xpack }, + }; + } + return localStats; }); }; diff --git a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_xpack.js b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_xpack.js deleted file mode 100644 index aaeb890981aa1..0000000000000 --- a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_xpack.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { TIMEOUT } from './constants'; - -/** - * Get the cluster stats from the connected cluster. - * - * This is the equivalent of GET /_license?local=true . - * - * Like any X-Pack related API, X-Pack must installed for this to work. - * - * @param {function} callCluster The callWithInternalUser handler (exposed for testing) - * @return {Promise} The response from Elasticsearch. - */ -export function getXPackLicense(callCluster) { - return callCluster('transport.request', { - method: 'GET', - path: '/_license', - query: { - // Fetching the local license is cheaper than getting it from the master and good enough - local: 'true', - // For versions >= 7.6 and < 8.0, this flag is needed otherwise 'platinum' is returned for 'enterprise' license. - accept_enterprise: 'true', - }, - }).then(({ license }) => license); -} - -/** - * Get the cluster stats from the connected cluster. - * - * This is the equivalent of GET /_xpack/usage?master_timeout=${TIMEOUT} - * - * Like any X-Pack related API, X-Pack must installed for this to work. - * - * @param {function} callCluster The callWithInternalUser handler (exposed for testing) - * @return {Promise} The response from Elasticsearch equivalent to GET /_cluster/stats. - */ -export function getXPackUsage(callCluster) { - return callCluster('transport.request', { - method: 'GET', - path: '/_xpack/usage', - query: { - master_timeout: TIMEOUT, - }, - }); -} - -/** - * Combine the X-Pack responses into a single response as Monitoring does already. - * - * @param {Object} license The license returned from /_license - * @param {Object} usage The usage details returned from /_xpack/usage - * @return {Object} An object containing both the license and usage. - */ -export function handleXPack(license, usage) { - return { - license, - stack_stats: { - xpack: usage, - }, - }; -} - -/** - * Combine all X-Pack requests as a singular request that is ignored upon failure. - * - * @param {function} callCluster The callWithInternalUser handler (exposed for testing) - * @return {Promise} - */ -export function getXPack(callCluster) { - return Promise.all([getXPackLicense(callCluster), getXPackUsage(callCluster)]) - .then(([license, xpack]) => { - return { - license, - xpack, - }; - }) - .catch(() => { - return {}; - }); -} diff --git a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_xpack.ts b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_xpack.ts new file mode 100644 index 0000000000000..9b69540007e5f --- /dev/null +++ b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/get_xpack.ts @@ -0,0 +1,25 @@ +/* + * 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 { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; +import { TIMEOUT } from './constants'; + +/** + * Get the cluster stats from the connected cluster. + * + * This is the equivalent of GET /_xpack/usage?master_timeout=${TIMEOUT} + * + * Like any X-Pack related API, X-Pack must installed for this to work. + */ +export function getXPackUsage(callCluster: CallCluster) { + return callCluster('transport.request', { + method: 'GET', + path: '/_xpack/usage', + query: { + master_timeout: TIMEOUT, + }, + }); +} diff --git a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/register_xpack_collection.ts b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/register_xpack_collection.ts index 57faf2da90d09..04445d7bde7d7 100644 --- a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/register_xpack_collection.ts +++ b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/register_xpack_collection.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { getLocalLicense } from '../../../../../../src/legacy/core_plugins/telemetry/server/telemetry_collection/get_local_license'; import { telemetryCollectionManager } from '../../../../../../src/legacy/core_plugins/telemetry/server'; import { getClusterUuids } from '../../../../../../src/legacy/core_plugins/telemetry/server/telemetry_collection'; import { getStatsWithXpack } from './get_stats_with_xpack'; @@ -15,5 +16,6 @@ export function registerMonitoringCollection() { priority: 1, statsGetter: getStatsWithXpack, clusterDetailsGetter: getClusterUuids, + licenseGetter: getLocalLicense, }); } diff --git a/x-pack/test/api_integration/apis/telemetry/fixtures/basiccluster.json b/x-pack/test/api_integration/apis/telemetry/fixtures/basiccluster.json index 5c3c8cfcab7a6..a0097f53ac93b 100644 --- a/x-pack/test/api_integration/apis/telemetry/fixtures/basiccluster.json +++ b/x-pack/test/api_integration/apis/telemetry/fixtures/basiccluster.json @@ -1,6 +1,7 @@ [ { "cluster_name": "docker-cluster", + "collectionSource": "monitoring", "cluster_stats": { "indices": { "completion": { @@ -161,6 +162,12 @@ }, "cluster_uuid": "ooEYzl3fSL222Y6eVm7SAA", "license": { + "uid": "79dc3adb-e85e-4cef-a985-9b74eb6c07c1", + "issue_date_in_millis": 1532383643540, + "issued_to": "docker-cluster", + "issuer": "elasticsearch", + "max_nodes": 1000, + "start_date_in_millis": -1, "issue_date": "2018-07-23T22:07:23.540Z", "status": "active", "type": "basic" diff --git a/x-pack/test/api_integration/apis/telemetry/fixtures/multicluster.json b/x-pack/test/api_integration/apis/telemetry/fixtures/multicluster.json index 2e6a75ee75972..6cc9c55157b28 100644 --- a/x-pack/test/api_integration/apis/telemetry/fixtures/multicluster.json +++ b/x-pack/test/api_integration/apis/telemetry/fixtures/multicluster.json @@ -1 +1,1001 @@ -[{"cluster_uuid":"6d-9tDFTRe-qT5GoBytdlQ","timestamp":"2017-08-15T22:10:59.952Z","cluster_name":"clustertwo","version":"7.0.0-alpha1","license":{"status":"active","type":"basic","issue_date":"2014-09-29T00:00:00.000Z","expiry_date":"2030-08-29T23:59:59.999Z","expiry_date_in_millis":1914278399999},"cluster_stats":{"timestamp":1502835059952,"status":"green","indices":{"count":1,"shards":{"total":1,"primaries":1,"replication":0,"index":{"shards":{"min":1,"max":1,"avg":1},"primaries":{"min":1,"max":1,"avg":1},"replication":{"min":0,"max":0,"avg":0}}},"docs":{"count":8,"deleted":0},"store":{"size_in_bytes":34095},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":8,"memory_in_bytes":13852,"terms_memory_in_bytes":10412,"stored_fields_memory_in_bytes":2496,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":256,"points_memory_in_bytes":8,"doc_values_memory_in_bytes":680,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}}},"nodes":{"count":{"total":1,"data":1,"coordinating_only":0,"master":1,"ingest":1},"versions":["7.0.0-alpha1"],"os":{"available_processors":4,"allocated_processors":1,"names":[{"name":"Mac OS X","count":1}],"mem":{"total_in_bytes":17179869184,"free_in_bytes":183799808,"used_in_bytes":16996069376,"free_percent":1,"used_percent":99}},"process":{"cpu":{"percent":0},"open_file_descriptors":{"min":163,"max":163,"avg":163}},"jvm":{"max_uptime_in_millis":701043,"versions":[{"vm_version":"25.121-b13","count":1,"vm_vendor":"Oracle Corporation","version":"1.8.0_121","vm_name":"Java HotSpot(TM) 64-Bit Server VM"}],"mem":{"heap_used_in_bytes":204299464,"heap_max_in_bytes":628555776},"threads":40},"fs":{"total_in_bytes":499065712640,"free_in_bytes":200665341952,"available_in_bytes":200403197952},"plugins":[{"classname":"org.elasticsearch.xpack.XPackPlugin","name":"x-pack","description":"Elasticsearch Expanded Pack Plugin","version":"7.0.0-alpha1","has_native_controller":true}],"network_types":{"transport_types":{"security4":1},"http_types":{"security4":1}}}},"stack_stats":{"xpack":{"security":{"available":false,"enabled":true,"realms":{"file":{"available":false,"enabled":false},"ldap":{"available":false,"enabled":false},"native":{"available":false,"enabled":false},"active_directory":{"available":false,"enabled":false},"pki":{"available":false,"enabled":false}},"roles":{"native":{"size":1,"dls":false,"fls":false},"file":{"size":0,"dls":false,"fls":false}},"role_mapping":{"native":{"size":0,"enabled":0}},"ssl":{"http":{"enabled":false}},"audit":{"outputs":["logfile"],"enabled":false},"ipfilter":{"http":false,"transport":false},"anonymous":{"enabled":false}},"monitoring":{"available":true,"enabled":true,"enabled_exporters":{"http":1}},"watcher":{"available":false,"enabled":true,"execution":{"actions":{"_all":{"total":0,"total_time_in_ms":0}}}},"graph":{"available":false,"enabled":true},"ml":{"available":false,"enabled":true,"jobs":{"_all":{"count":0,"detectors":{"total":0,"min":0,"avg":0,"max":0},"model_size":{"total":0,"min":0,"avg":0,"max":0}}},"datafeeds":{"_all":{"count":0}}},"logstash":{"available":false,"enabled":true},"ccr":{"auto_follow_patterns_count":0,"available":true,"follower_indices_count":0,"enabled":true}}}},{"cluster_uuid":"lOF8kofiS_2DX58o9mXJ1Q","timestamp":"2017-08-15T22:10:54.610Z","cluster_name":"monitoring-one","version":"7.0.0-alpha1","license":{"status":"active","type":"trial","issue_date":"2017-08-15T21:58:28.997Z","expiry_date":"2017-09-14T21:58:28.997Z","expiry_date_in_millis":1505426308997},"cluster_stats":{"timestamp":1502835054610,"status":"yellow","indices":{"count":8,"shards":{"total":8,"primaries":8,"replication":0,"index":{"shards":{"min":1,"max":1,"avg":1},"primaries":{"min":1,"max":1,"avg":1},"replication":{"min":0,"max":0,"avg":0}}},"docs":{"count":3997,"deleted":69},"store":{"size_in_bytes":2647163},"fielddata":{"memory_size_in_bytes":2104,"evictions":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":36,"memory_in_bytes":278961,"terms_memory_in_bytes":166031,"stored_fields_memory_in_bytes":11544,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":6784,"points_memory_in_bytes":3250,"doc_values_memory_in_bytes":91352,"index_writer_memory_in_bytes":205347,"version_map_memory_in_bytes":26362,"fixed_bit_set_memory_in_bytes":992,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}}},"nodes":{"count":{"total":1,"data":1,"coordinating_only":0,"master":1,"ingest":1},"versions":["7.0.0-alpha1"],"os":{"available_processors":4,"allocated_processors":1,"names":[{"name":"Mac OS X","count":1}],"mem":{"total_in_bytes":17179869184,"free_in_bytes":86732800,"used_in_bytes":17093136384,"free_percent":1,"used_percent":99}},"process":{"cpu":{"percent":2},"open_file_descriptors":{"min":178,"max":178,"avg":178}},"jvm":{"max_uptime_in_millis":761002,"versions":[{"vm_version":"25.121-b13","count":1,"vm_vendor":"Oracle Corporation","version":"1.8.0_121","vm_name":"Java HotSpot(TM) 64-Bit Server VM"}],"mem":{"heap_used_in_bytes":133041176,"heap_max_in_bytes":628555776},"threads":42},"fs":{"total_in_bytes":499065712640,"free_in_bytes":200665792512,"available_in_bytes":200403648512},"plugins":[{"classname":"org.elasticsearch.xpack.XPackPlugin","name":"x-pack","description":"Elasticsearch Expanded Pack Plugin","version":"7.0.0-alpha1","has_native_controller":true}],"network_types":{"transport_types":{"security4":1},"http_types":{"security4":1}}}},"stack_stats":{"xpack":{"security":{"available":true,"enabled":true,"realms":{"file":{"name":["default_file"],"available":true,"size":[0],"enabled":true,"order":[2147483647]},"ldap":{"available":true,"enabled":false},"native":{"name":["default_native"],"available":true,"size":[2],"enabled":true,"order":[2147483647]},"active_directory":{"available":true,"enabled":false},"pki":{"available":true,"enabled":false}},"roles":{"native":{"size":1,"dls":false,"fls":false},"file":{"size":0,"dls":false,"fls":false}},"role_mapping":{"native":{"size":0,"enabled":0}},"ssl":{"http":{"enabled":false}},"audit":{"outputs":["logfile"],"enabled":false},"ipfilter":{"http":false,"transport":false},"anonymous":{"enabled":false}},"monitoring":{"available":true,"enabled":true,"enabled_exporters":{"local":1}},"watcher":{"available":true,"enabled":true,"execution":{"actions":{"index":{"total":14,"total_time_in_ms":158},"_all":{"total":110,"total_time_in_ms":2245},"email":{"total":14,"total_time_in_ms":3}}}},"graph":{"available":true,"enabled":true},"ml":{"available":true,"enabled":true,"jobs":{"_all":{"count":0,"detectors":{"total":0,"min":0,"avg":0,"max":0},"model_size":{"total":0,"min":0,"avg":0,"max":0}}},"datafeeds":{"_all":{"count":0}}},"logstash":{"available":true,"enabled":true},"ccr":{"auto_follow_patterns_count":0,"available":true,"follower_indices_count":0,"enabled":true}}}},{"cluster_uuid":"TkHOX_-1TzWwbROwQJU5IA","timestamp":"2017-08-15T22:10:52.642Z","cluster_name":"clusterone","version":"7.0.0-alpha1","license":{"status":"active","type":"trial","issue_date":"2017-08-15T21:58:47.135Z","expiry_date":"2017-09-14T21:58:47.135Z","expiry_date_in_millis":1505426327135},"cluster_stats":{"timestamp":1502835052641,"status":"green","indices":{"count":5,"shards":{"total":26,"primaries":13,"replication":1,"index":{"shards":{"min":2,"max":10,"avg":5.2},"primaries":{"min":1,"max":5,"avg":2.6},"replication":{"min":1,"max":1,"avg":1}}},"docs":{"count":150,"deleted":0},"store":{"size_in_bytes":4838464},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":76,"memory_in_bytes":1907922,"terms_memory_in_bytes":1595112,"stored_fields_memory_in_bytes":23744,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":197184,"points_memory_in_bytes":3818,"doc_values_memory_in_bytes":88064,"index_writer_memory_in_bytes":7006184,"version_map_memory_in_bytes":260,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":1502834982386,"file_sizes":{}}},"nodes":{"count":{"total":2,"data":2,"coordinating_only":0,"master":2,"ingest":2},"versions":["7.0.0-alpha1"],"os":{"available_processors":8,"allocated_processors":2,"names":[{"name":"Mac OS X","count":2}],"mem":{"total_in_bytes":34359738368,"free_in_bytes":332099584,"used_in_bytes":34027638784,"free_percent":1,"used_percent":99}},"process":{"cpu":{"percent":2},"open_file_descriptors":{"min":218,"max":237,"avg":227}},"jvm":{"max_uptime_in_millis":741786,"versions":[{"vm_version":"25.121-b13","count":2,"vm_vendor":"Oracle Corporation","version":"1.8.0_121","vm_name":"Java HotSpot(TM) 64-Bit Server VM"}],"mem":{"heap_used_in_bytes":465621856,"heap_max_in_bytes":1257111552},"threads":92},"fs":{"total_in_bytes":499065712640,"free_in_bytes":200666353664,"available_in_bytes":200404209664},"plugins":[{"classname":"org.elasticsearch.xpack.XPackPlugin","name":"x-pack","description":"Elasticsearch Expanded Pack Plugin","version":"7.0.0-alpha1","has_native_controller":true}],"network_types":{"transport_types":{"security4":2},"http_types":{"security4":2}}}},"stack_stats":{"xpack":{"security":{"available":true,"enabled":true,"realms":{"file":{"name":["default_file"],"available":true,"size":[0],"enabled":true,"order":[2147483647]},"ldap":{"available":true,"enabled":false},"native":{"name":["default_native"],"available":true,"size":[1],"enabled":true,"order":[2147483647]},"active_directory":{"available":true,"enabled":false},"pki":{"available":true,"enabled":false}},"roles":{"native":{"size":1,"dls":false,"fls":false},"file":{"size":0,"dls":false,"fls":false}},"role_mapping":{"native":{"size":0,"enabled":0}},"ssl":{"http":{"enabled":false}},"audit":{"outputs":["logfile"],"enabled":false},"ipfilter":{"http":false,"transport":false},"anonymous":{"enabled":false}},"monitoring":{"available":true,"enabled":true,"enabled_exporters":{"http":1}},"watcher":{"available":true,"enabled":true,"execution":{"actions":{"_all":{"total":0,"total_time_in_ms":0}}}},"graph":{"available":true,"enabled":true,"graph_workspace":{"total":0}},"ml":{"available":true,"enabled":true,"jobs":{"_all":{"count":3,"detectors":{"total":3,"min":1,"avg":1,"max":1},"model_size":{"total":0,"min":0,"avg":0,"max":0}},"opened":{"count":1,"detectors":{"total":1,"min":1,"avg":1,"max":1},"model_size":{"total":0,"min":0,"avg":0,"max":0}},"closed":{"count":2,"detectors":{"total":2,"min":1,"avg":1,"max":1},"model_size":{"total":0,"min":0,"avg":0,"max":0}}},"datafeeds":{"_all":{"count":0}}},"logstash":{"available":true,"enabled":true},"ccr":{"auto_follow_patterns_count":0,"available":true,"follower_indices_count":0,"enabled":true}},"kibana":{"count":1,"versions":[{"version":"7.0.0-alpha1","count":1}],"os":{"platforms":[],"platformReleases":[],"distros":[],"distroReleases":[]},"dashboard":{"total":0},"visualization":{"total":0},"search":{"total":0},"index_pattern":{"total":0},"graph_workspace":{"total":0},"timelion_sheet":{"total":0},"indices":1,"plugins":{}},"logstash":{"count":1,"versions":[{"version":"7.0.0-alpha1","count":1}],"os":{"platforms":[],"platformReleases":[],"distros":[],"distroReleases":[]}}}}] +[ + { + "cluster_uuid": "6d-9tDFTRe-qT5GoBytdlQ", + "collectionSource": "monitoring", + "timestamp": "2017-08-15T22:10:59.952Z", + "cluster_name": "clustertwo", + "version": "7.0.0-alpha1", + "license": { + "status": "active", + "type": "basic", + "issue_date": "2014-09-29T00:00:00.000Z", + "expiry_date": "2030-08-29T23:59:59.999Z", + "expiry_date_in_millis": 1914278399999, + "issue_date_in_millis": 1411948800000, + "issued_to": "issuedTo", + "issuer": "issuer", + "max_nodes": 1, + "uid": "893361dc-9749-4997-93cb-802e3d7fa4a8", + "hkey": null + }, + "cluster_stats": { + "timestamp": 1502835059952, + "status": "green", + "indices": { + "count": 1, + "shards": { + "total": 1, + "primaries": 1, + "replication": 0, + "index": { + "shards": { + "min": 1, + "max": 1, + "avg": 1 + }, + "primaries": { + "min": 1, + "max": 1, + "avg": 1 + }, + "replication": { + "min": 0, + "max": 0, + "avg": 0 + } + } + }, + "docs": { + "count": 8, + "deleted": 0 + }, + "store": { + "size_in_bytes": 34095 + }, + "fielddata": { + "memory_size_in_bytes": 0, + "evictions": 0 + }, + "query_cache": { + "memory_size_in_bytes": 0, + "total_count": 0, + "hit_count": 0, + "miss_count": 0, + "cache_size": 0, + "cache_count": 0, + "evictions": 0 + }, + "completion": { + "size_in_bytes": 0 + }, + "segments": { + "count": 8, + "memory_in_bytes": 13852, + "terms_memory_in_bytes": 10412, + "stored_fields_memory_in_bytes": 2496, + "term_vectors_memory_in_bytes": 0, + "norms_memory_in_bytes": 256, + "points_memory_in_bytes": 8, + "doc_values_memory_in_bytes": 680, + "index_writer_memory_in_bytes": 0, + "version_map_memory_in_bytes": 0, + "fixed_bit_set_memory_in_bytes": 0, + "max_unsafe_auto_id_timestamp": -1, + "file_sizes": {} + } + }, + "nodes": { + "count": { + "total": 1, + "data": 1, + "coordinating_only": 0, + "master": 1, + "ingest": 1 + }, + "versions": [ + "7.0.0-alpha1" + ], + "os": { + "available_processors": 4, + "allocated_processors": 1, + "names": [ + { + "name": "Mac OS X", + "count": 1 + } + ], + "mem": { + "total_in_bytes": 17179869184, + "free_in_bytes": 183799808, + "used_in_bytes": 16996069376, + "free_percent": 1, + "used_percent": 99 + } + }, + "process": { + "cpu": { + "percent": 0 + }, + "open_file_descriptors": { + "min": 163, + "max": 163, + "avg": 163 + } + }, + "jvm": { + "max_uptime_in_millis": 701043, + "versions": [ + { + "vm_version": "25.121-b13", + "count": 1, + "vm_vendor": "Oracle Corporation", + "version": "1.8.0_121", + "vm_name": "Java HotSpot(TM) 64-Bit Server VM" + } + ], + "mem": { + "heap_used_in_bytes": 204299464, + "heap_max_in_bytes": 628555776 + }, + "threads": 40 + }, + "fs": { + "total_in_bytes": 499065712640, + "free_in_bytes": 200665341952, + "available_in_bytes": 200403197952 + }, + "plugins": [ + { + "classname": "org.elasticsearch.xpack.XPackPlugin", + "name": "x-pack", + "description": "Elasticsearch Expanded Pack Plugin", + "version": "7.0.0-alpha1", + "has_native_controller": true + } + ], + "network_types": { + "transport_types": { + "security4": 1 + }, + "http_types": { + "security4": 1 + } + } + } + }, + "stack_stats": { + "xpack": { + "security": { + "available": false, + "enabled": true, + "realms": { + "file": { + "available": false, + "enabled": false + }, + "ldap": { + "available": false, + "enabled": false + }, + "native": { + "available": false, + "enabled": false + }, + "active_directory": { + "available": false, + "enabled": false + }, + "pki": { + "available": false, + "enabled": false + } + }, + "roles": { + "native": { + "size": 1, + "dls": false, + "fls": false + }, + "file": { + "size": 0, + "dls": false, + "fls": false + } + }, + "role_mapping": { + "native": { + "size": 0, + "enabled": 0 + } + }, + "ssl": { + "http": { + "enabled": false + } + }, + "audit": { + "outputs": [ + "logfile" + ], + "enabled": false + }, + "ipfilter": { + "http": false, + "transport": false + }, + "anonymous": { + "enabled": false + } + }, + "monitoring": { + "available": true, + "enabled": true, + "enabled_exporters": { + "http": 1 + } + }, + "watcher": { + "available": false, + "enabled": true, + "execution": { + "actions": { + "_all": { + "total": 0, + "total_time_in_ms": 0 + } + } + } + }, + "graph": { + "available": false, + "enabled": true + }, + "ml": { + "available": false, + "enabled": true, + "jobs": { + "_all": { + "count": 0, + "detectors": { + "total": 0, + "min": 0, + "avg": 0, + "max": 0 + }, + "model_size": { + "total": 0, + "min": 0, + "avg": 0, + "max": 0 + } + } + }, + "datafeeds": { + "_all": { + "count": 0 + } + } + }, + "logstash": { + "available": false, + "enabled": true + }, + "ccr": { + "auto_follow_patterns_count": 0, + "available": true, + "follower_indices_count": 0, + "enabled": true + } + } + } + }, + { + "cluster_uuid": "lOF8kofiS_2DX58o9mXJ1Q", + "collectionSource": "monitoring", + "timestamp": "2017-08-15T22:10:54.610Z", + "cluster_name": "monitoring-one", + "version": "7.0.0-alpha1", + "license": { + "status": "active", + "type": "trial", + "issue_date": "2017-08-15T21:58:28.997Z", + "expiry_date": "2017-09-14T21:58:28.997Z", + "expiry_date_in_millis": 1505426308997, + "issue_date_in_millis": 1502834308997, + "issued_to": "monitoring-one", + "issuer": "elasticsearch", + "max_nodes": 1000, + "start_date_in_millis": -1, + "uid": "e5f6e897-0db5-4042-ad7c-6628ddc91691", + "hkey": null + }, + "cluster_stats": { + "timestamp": 1502835054610, + "status": "yellow", + "indices": { + "count": 8, + "shards": { + "total": 8, + "primaries": 8, + "replication": 0, + "index": { + "shards": { + "min": 1, + "max": 1, + "avg": 1 + }, + "primaries": { + "min": 1, + "max": 1, + "avg": 1 + }, + "replication": { + "min": 0, + "max": 0, + "avg": 0 + } + } + }, + "docs": { + "count": 3997, + "deleted": 69 + }, + "store": { + "size_in_bytes": 2647163 + }, + "fielddata": { + "memory_size_in_bytes": 2104, + "evictions": 0 + }, + "query_cache": { + "memory_size_in_bytes": 0, + "total_count": 0, + "hit_count": 0, + "miss_count": 0, + "cache_size": 0, + "cache_count": 0, + "evictions": 0 + }, + "completion": { + "size_in_bytes": 0 + }, + "segments": { + "count": 36, + "memory_in_bytes": 278961, + "terms_memory_in_bytes": 166031, + "stored_fields_memory_in_bytes": 11544, + "term_vectors_memory_in_bytes": 0, + "norms_memory_in_bytes": 6784, + "points_memory_in_bytes": 3250, + "doc_values_memory_in_bytes": 91352, + "index_writer_memory_in_bytes": 205347, + "version_map_memory_in_bytes": 26362, + "fixed_bit_set_memory_in_bytes": 992, + "max_unsafe_auto_id_timestamp": -1, + "file_sizes": {} + } + }, + "nodes": { + "count": { + "total": 1, + "data": 1, + "coordinating_only": 0, + "master": 1, + "ingest": 1 + }, + "versions": [ + "7.0.0-alpha1" + ], + "os": { + "available_processors": 4, + "allocated_processors": 1, + "names": [ + { + "name": "Mac OS X", + "count": 1 + } + ], + "mem": { + "total_in_bytes": 17179869184, + "free_in_bytes": 86732800, + "used_in_bytes": 17093136384, + "free_percent": 1, + "used_percent": 99 + } + }, + "process": { + "cpu": { + "percent": 2 + }, + "open_file_descriptors": { + "min": 178, + "max": 178, + "avg": 178 + } + }, + "jvm": { + "max_uptime_in_millis": 761002, + "versions": [ + { + "vm_version": "25.121-b13", + "count": 1, + "vm_vendor": "Oracle Corporation", + "version": "1.8.0_121", + "vm_name": "Java HotSpot(TM) 64-Bit Server VM" + } + ], + "mem": { + "heap_used_in_bytes": 133041176, + "heap_max_in_bytes": 628555776 + }, + "threads": 42 + }, + "fs": { + "total_in_bytes": 499065712640, + "free_in_bytes": 200665792512, + "available_in_bytes": 200403648512 + }, + "plugins": [ + { + "classname": "org.elasticsearch.xpack.XPackPlugin", + "name": "x-pack", + "description": "Elasticsearch Expanded Pack Plugin", + "version": "7.0.0-alpha1", + "has_native_controller": true + } + ], + "network_types": { + "transport_types": { + "security4": 1 + }, + "http_types": { + "security4": 1 + } + } + } + }, + "stack_stats": { + "xpack": { + "security": { + "available": true, + "enabled": true, + "realms": { + "file": { + "name": [ + "default_file" + ], + "available": true, + "size": [ + 0 + ], + "enabled": true, + "order": [ + 2147483647 + ] + }, + "ldap": { + "available": true, + "enabled": false + }, + "native": { + "name": [ + "default_native" + ], + "available": true, + "size": [ + 2 + ], + "enabled": true, + "order": [ + 2147483647 + ] + }, + "active_directory": { + "available": true, + "enabled": false + }, + "pki": { + "available": true, + "enabled": false + } + }, + "roles": { + "native": { + "size": 1, + "dls": false, + "fls": false + }, + "file": { + "size": 0, + "dls": false, + "fls": false + } + }, + "role_mapping": { + "native": { + "size": 0, + "enabled": 0 + } + }, + "ssl": { + "http": { + "enabled": false + } + }, + "audit": { + "outputs": [ + "logfile" + ], + "enabled": false + }, + "ipfilter": { + "http": false, + "transport": false + }, + "anonymous": { + "enabled": false + } + }, + "monitoring": { + "available": true, + "enabled": true, + "enabled_exporters": { + "local": 1 + } + }, + "watcher": { + "available": true, + "enabled": true, + "execution": { + "actions": { + "index": { + "total": 14, + "total_time_in_ms": 158 + }, + "_all": { + "total": 110, + "total_time_in_ms": 2245 + }, + "email": { + "total": 14, + "total_time_in_ms": 3 + } + } + } + }, + "graph": { + "available": true, + "enabled": true + }, + "ml": { + "available": true, + "enabled": true, + "jobs": { + "_all": { + "count": 0, + "detectors": { + "total": 0, + "min": 0, + "avg": 0, + "max": 0 + }, + "model_size": { + "total": 0, + "min": 0, + "avg": 0, + "max": 0 + } + } + }, + "datafeeds": { + "_all": { + "count": 0 + } + } + }, + "logstash": { + "available": true, + "enabled": true + }, + "ccr": { + "auto_follow_patterns_count": 0, + "available": true, + "follower_indices_count": 0, + "enabled": true + } + } + } + }, + { + "cluster_uuid": "TkHOX_-1TzWwbROwQJU5IA", + "collectionSource": "monitoring", + "timestamp": "2017-08-15T22:10:52.642Z", + "cluster_name": "clusterone", + "version": "7.0.0-alpha1", + "license": { + "status": "active", + "type": "trial", + "issue_date": "2017-08-15T21:58:47.135Z", + "expiry_date": "2017-09-14T21:58:47.135Z", + "expiry_date_in_millis": 1505426327135, + "issue_date_in_millis": 1502834327135, + "issued_to": "clusterone", + "issuer": "elasticsearch", + "max_nodes": 1000, + "start_date_in_millis": -1, + "uid": "e5e99511-0928-41a3-97b0-ec77fa5e3b4c", + "hkey": null + }, + "cluster_stats": { + "timestamp": 1502835052641, + "status": "green", + "indices": { + "count": 5, + "shards": { + "total": 26, + "primaries": 13, + "replication": 1, + "index": { + "shards": { + "min": 2, + "max": 10, + "avg": 5.2 + }, + "primaries": { + "min": 1, + "max": 5, + "avg": 2.6 + }, + "replication": { + "min": 1, + "max": 1, + "avg": 1 + } + } + }, + "docs": { + "count": 150, + "deleted": 0 + }, + "store": { + "size_in_bytes": 4838464 + }, + "fielddata": { + "memory_size_in_bytes": 0, + "evictions": 0 + }, + "query_cache": { + "memory_size_in_bytes": 0, + "total_count": 0, + "hit_count": 0, + "miss_count": 0, + "cache_size": 0, + "cache_count": 0, + "evictions": 0 + }, + "completion": { + "size_in_bytes": 0 + }, + "segments": { + "count": 76, + "memory_in_bytes": 1907922, + "terms_memory_in_bytes": 1595112, + "stored_fields_memory_in_bytes": 23744, + "term_vectors_memory_in_bytes": 0, + "norms_memory_in_bytes": 197184, + "points_memory_in_bytes": 3818, + "doc_values_memory_in_bytes": 88064, + "index_writer_memory_in_bytes": 7006184, + "version_map_memory_in_bytes": 260, + "fixed_bit_set_memory_in_bytes": 0, + "max_unsafe_auto_id_timestamp": 1502834982386, + "file_sizes": {} + } + }, + "nodes": { + "count": { + "total": 2, + "data": 2, + "coordinating_only": 0, + "master": 2, + "ingest": 2 + }, + "versions": [ + "7.0.0-alpha1" + ], + "os": { + "available_processors": 8, + "allocated_processors": 2, + "names": [ + { + "name": "Mac OS X", + "count": 2 + } + ], + "mem": { + "total_in_bytes": 34359738368, + "free_in_bytes": 332099584, + "used_in_bytes": 34027638784, + "free_percent": 1, + "used_percent": 99 + } + }, + "process": { + "cpu": { + "percent": 2 + }, + "open_file_descriptors": { + "min": 218, + "max": 237, + "avg": 227 + } + }, + "jvm": { + "max_uptime_in_millis": 741786, + "versions": [ + { + "vm_version": "25.121-b13", + "count": 2, + "vm_vendor": "Oracle Corporation", + "version": "1.8.0_121", + "vm_name": "Java HotSpot(TM) 64-Bit Server VM" + } + ], + "mem": { + "heap_used_in_bytes": 465621856, + "heap_max_in_bytes": 1257111552 + }, + "threads": 92 + }, + "fs": { + "total_in_bytes": 499065712640, + "free_in_bytes": 200666353664, + "available_in_bytes": 200404209664 + }, + "plugins": [ + { + "classname": "org.elasticsearch.xpack.XPackPlugin", + "name": "x-pack", + "description": "Elasticsearch Expanded Pack Plugin", + "version": "7.0.0-alpha1", + "has_native_controller": true + } + ], + "network_types": { + "transport_types": { + "security4": 2 + }, + "http_types": { + "security4": 2 + } + } + } + }, + "stack_stats": { + "xpack": { + "security": { + "available": true, + "enabled": true, + "realms": { + "file": { + "name": [ + "default_file" + ], + "available": true, + "size": [ + 0 + ], + "enabled": true, + "order": [ + 2147483647 + ] + }, + "ldap": { + "available": true, + "enabled": false + }, + "native": { + "name": [ + "default_native" + ], + "available": true, + "size": [ + 1 + ], + "enabled": true, + "order": [ + 2147483647 + ] + }, + "active_directory": { + "available": true, + "enabled": false + }, + "pki": { + "available": true, + "enabled": false + } + }, + "roles": { + "native": { + "size": 1, + "dls": false, + "fls": false + }, + "file": { + "size": 0, + "dls": false, + "fls": false + } + }, + "role_mapping": { + "native": { + "size": 0, + "enabled": 0 + } + }, + "ssl": { + "http": { + "enabled": false + } + }, + "audit": { + "outputs": [ + "logfile" + ], + "enabled": false + }, + "ipfilter": { + "http": false, + "transport": false + }, + "anonymous": { + "enabled": false + } + }, + "monitoring": { + "available": true, + "enabled": true, + "enabled_exporters": { + "http": 1 + } + }, + "watcher": { + "available": true, + "enabled": true, + "execution": { + "actions": { + "_all": { + "total": 0, + "total_time_in_ms": 0 + } + } + } + }, + "graph": { + "available": true, + "enabled": true, + "graph_workspace": { + "total": 0 + } + }, + "ml": { + "available": true, + "enabled": true, + "jobs": { + "_all": { + "count": 3, + "detectors": { + "total": 3, + "min": 1, + "avg": 1, + "max": 1 + }, + "model_size": { + "total": 0, + "min": 0, + "avg": 0, + "max": 0 + } + }, + "opened": { + "count": 1, + "detectors": { + "total": 1, + "min": 1, + "avg": 1, + "max": 1 + }, + "model_size": { + "total": 0, + "min": 0, + "avg": 0, + "max": 0 + } + }, + "closed": { + "count": 2, + "detectors": { + "total": 2, + "min": 1, + "avg": 1, + "max": 1 + }, + "model_size": { + "total": 0, + "min": 0, + "avg": 0, + "max": 0 + } + } + }, + "datafeeds": { + "_all": { + "count": 0 + } + } + }, + "logstash": { + "available": true, + "enabled": true + }, + "ccr": { + "auto_follow_patterns_count": 0, + "available": true, + "follower_indices_count": 0, + "enabled": true + } + }, + "kibana": { + "count": 1, + "versions": [ + { + "version": "7.0.0-alpha1", + "count": 1 + } + ], + "os": { + "platforms": [], + "platformReleases": [], + "distros": [], + "distroReleases": [] + }, + "dashboard": { + "total": 0 + }, + "visualization": { + "total": 0 + }, + "search": { + "total": 0 + }, + "index_pattern": { + "total": 0 + }, + "graph_workspace": { + "total": 0 + }, + "timelion_sheet": { + "total": 0 + }, + "indices": 1, + "plugins": {} + }, + "logstash": { + "count": 1, + "versions": [ + { + "version": "7.0.0-alpha1", + "count": 1 + } + ], + "os": { + "platforms": [], + "platformReleases": [], + "distros": [], + "distroReleases": [] + } + } + } + } +] From 900a8290fb9b544e958089adc03aeee34786b7f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 25 Feb 2020 11:52:37 +0100 Subject: [PATCH 045/123] [Logs UI] Unskip and stabilitize log column configuration tests (#58392) This attempts to make the log column configuration tests more robust to inconsistent DOM and interaction timing. fixes #58059 --- .../apps/infra/logs_source_configuration.ts | 3 +- .../infra_source_configuration_form.ts | 30 +++++++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/x-pack/test/functional/apps/infra/logs_source_configuration.ts b/x-pack/test/functional/apps/infra/logs_source_configuration.ts index 1dfbe3526ce40..ecad5a40ec42e 100644 --- a/x-pack/test/functional/apps/infra/logs_source_configuration.ts +++ b/x-pack/test/functional/apps/infra/logs_source_configuration.ts @@ -15,8 +15,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const pageObjects = getPageObjects(['common', 'infraLogs']); const retry = getService('retry'); - // FLAKY: https://github.com/elastic/kibana/issues/58059 - describe.skip('Logs Source Configuration', function() { + describe('Logs Source Configuration', function() { this.tags('smoke'); before(async () => { diff --git a/x-pack/test/functional/services/infra_source_configuration_form.ts b/x-pack/test/functional/services/infra_source_configuration_form.ts index ab61d5232fa1c..dbae6f00f75a2 100644 --- a/x-pack/test/functional/services/infra_source_configuration_form.ts +++ b/x-pack/test/functional/services/infra_source_configuration_form.ts @@ -36,25 +36,37 @@ export function InfraSourceConfigurationFormProvider({ getService }: FtrProvider return await testSubjects.find('~addLogColumnPopover'); }, async addTimestampLogColumn() { - await (await this.getAddLogColumnButton()).click(); + // try to open the popover + const popover = await retry.try(async () => { + await (await this.getAddLogColumnButton()).click(); + return this.getAddLogColumnPopover(); + }); + + // try to select the timestamp field await retry.try(async () => { - await ( - await testSubjects.findDescendant( - '~addTimestampLogColumn', - await this.getAddLogColumnPopover() - ) - ).click(); + await (await testSubjects.findDescendant('~addTimestampLogColumn', popover)).click(); }); + + // wait for timestamp panel to show up + await testSubjects.findDescendant('~systemLogColumnPanel:Timestamp', await this.getForm()); }, async addFieldLogColumn(fieldName: string) { - await (await this.getAddLogColumnButton()).click(); + // try to open the popover + const popover = await retry.try(async () => { + await (await this.getAddLogColumnButton()).click(); + return this.getAddLogColumnPopover(); + }); + + // try to select the given field await retry.try(async () => { - const popover = await this.getAddLogColumnPopover(); await (await testSubjects.findDescendant('~fieldSearchInput', popover)).type(fieldName); await ( await testSubjects.findDescendant(`~addFieldLogColumn:${fieldName}`, popover) ).click(); }); + + // wait for field panel to show up + await testSubjects.findDescendant(`~fieldLogColumnPanel:${fieldName}`, await this.getForm()); }, async getLogColumnPanels(): Promise { return await testSubjects.findAllDescendant('~logColumnPanel', await this.getForm()); From 31cc2015b73e1035acf409373890ffef7d475b60 Mon Sep 17 00:00:00 2001 From: David Roberts Date: Tue, 25 Feb 2020 12:18:35 +0000 Subject: [PATCH 046/123] [ML] Use event.timezone instead of beat.timezone in file upload (#58447) This is because beat.timezone was renamed to event.timezone in elastic/beats#9458 The corresponding file structure finder change is elastic/elasticsearch#52720 --- .../components/import_view/importer/importer.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/importer/importer.js b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/importer/importer.js index 710fa49e64167..27899a58beed2 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/importer/importer.js +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/importer/importer.js @@ -148,17 +148,17 @@ function populateFailures(error, failures, chunkCount) { } } -// The file structure endpoint sets the timezone to be {{ beat.timezone }} +// The file structure endpoint sets the timezone to be {{ event.timezone }} // as that's the variable Filebeat would send the client timezone in. // In this data import function the UI is effectively performing the role of Filebeat, // i.e. doing basic parsing, processing and conversion to JSON before forwarding to the ingest pipeline. // But it's not sending every single field that Filebeat would add, so the ingest pipeline -// cannot look for a beat.timezone variable in each input record. -// Therefore we need to replace {{ beat.timezone }} with the actual browser timezone +// cannot look for a event.timezone variable in each input record. +// Therefore we need to replace {{ event.timezone }} with the actual browser timezone function updatePipelineTimezone(ingestPipeline) { if (ingestPipeline !== undefined && ingestPipeline.processors && ingestPipeline.processors) { const dateProcessor = ingestPipeline.processors.find( - p => p.date !== undefined && p.date.timezone === '{{ beat.timezone }}' + p => p.date !== undefined && p.date.timezone === '{{ event.timezone }}' ); if (dateProcessor) { From 6fc6cb8b363b4a1ea7e07ce8d491874ca4fbb864 Mon Sep 17 00:00:00 2001 From: Robert Oskamp Date: Tue, 25 Feb 2020 13:22:29 +0100 Subject: [PATCH 047/123] [ML] Functional tests - adjust classification model memory (#58445) This PR increases the model memory setting in the classification creation test. --- .../data_frame_analytics/classification_creation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/machine_learning/data_frame_analytics/classification_creation.ts b/x-pack/test/functional/apps/machine_learning/data_frame_analytics/classification_creation.ts index 798a04cae3740..1bcdeef394c00 100644 --- a/x-pack/test/functional/apps/machine_learning/data_frame_analytics/classification_creation.ts +++ b/x-pack/test/functional/apps/machine_learning/data_frame_analytics/classification_creation.ts @@ -36,7 +36,7 @@ export default function({ getService }: FtrProviderContext) { }, dependentVariable: 'y', trainingPercent: '20', - modelMemory: '105mb', + modelMemory: '200mb', createIndexPattern: true, expected: { row: { From db276d18945246421068e480c7dd5322487cb276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez?= Date: Tue, 25 Feb 2020 13:39:13 +0100 Subject: [PATCH 048/123] =?UTF-8?q?[Logs=20/=20Metrics=20UI]=20Remove=20pa?= =?UTF-8?q?th=20prefix=20from=20ViewSourceConfigur=E2=80=A6=20(#58238)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the NP the routes have already the app name on them. Adding it to this button made the app name double /app/metrics/metrics/settings /app/logs/logs/settings The button only needs to go to the settings page within the app where it's being loaded, so we can safely drop the prefix. Closes #58233 --- .../public/components/source_configuration/index.ts | 5 +---- .../view_source_configuration_button.tsx | 9 +-------- .../public/pages/infrastructure/snapshot/index.tsx | 10 ++-------- .../pages/logs/stream/page_no_indices_content.tsx | 10 ++-------- .../public/pages/metrics/components/invalid_node.tsx | 10 ++-------- 5 files changed, 8 insertions(+), 36 deletions(-) diff --git a/x-pack/plugins/infra/public/components/source_configuration/index.ts b/x-pack/plugins/infra/public/components/source_configuration/index.ts index 4879a53ca329d..98825567cc204 100644 --- a/x-pack/plugins/infra/public/components/source_configuration/index.ts +++ b/x-pack/plugins/infra/public/components/source_configuration/index.ts @@ -5,7 +5,4 @@ */ export { SourceConfigurationSettings } from './source_configuration_settings'; -export { - ViewSourceConfigurationButton, - ViewSourceConfigurationButtonHrefBase, -} from './view_source_configuration_button'; +export { ViewSourceConfigurationButton } from './view_source_configuration_button'; diff --git a/x-pack/plugins/infra/public/components/source_configuration/view_source_configuration_button.tsx b/x-pack/plugins/infra/public/components/source_configuration/view_source_configuration_button.tsx index 9b584b2ef3bd0..9c3a40fb7ecf0 100644 --- a/x-pack/plugins/infra/public/components/source_configuration/view_source_configuration_button.tsx +++ b/x-pack/plugins/infra/public/components/source_configuration/view_source_configuration_button.tsx @@ -8,23 +8,16 @@ import { EuiButton } from '@elastic/eui'; import React from 'react'; import { Route } from 'react-router-dom'; -export enum ViewSourceConfigurationButtonHrefBase { - infrastructure = 'infrastructure', - logs = 'logs', -} - interface ViewSourceConfigurationButtonProps { 'data-test-subj'?: string; - hrefBase: ViewSourceConfigurationButtonHrefBase; children: React.ReactNode; } export const ViewSourceConfigurationButton = ({ 'data-test-subj': dataTestSubj, - hrefBase, children, }: ViewSourceConfigurationButtonProps) => { - const href = `/${hrefBase}/settings`; + const href = '/settings'; return ( {
{uiCapabilities?.infrastructure?.configureSource ? ( - + {i18n.translate('xpack.infra.configureSourceActionLabel', { defaultMessage: 'Change source configuration', })} diff --git a/x-pack/plugins/infra/public/pages/logs/stream/page_no_indices_content.tsx b/x-pack/plugins/infra/public/pages/logs/stream/page_no_indices_content.tsx index 1294007240027..739bad5689a96 100644 --- a/x-pack/plugins/infra/public/pages/logs/stream/page_no_indices_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/stream/page_no_indices_content.tsx @@ -10,10 +10,7 @@ import { identity } from 'fp-ts/lib/function'; import React from 'react'; import { NoIndices } from '../../../components/empty_states/no_indices'; -import { - ViewSourceConfigurationButton, - ViewSourceConfigurationButtonHrefBase, -} from '../../../components/source_configuration'; +import { ViewSourceConfigurationButton } from '../../../components/source_configuration'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; export const LogsPageNoIndicesContent = () => { @@ -49,10 +46,7 @@ export const LogsPageNoIndicesContent = () => { {canConfigureSource ? ( - + {i18n.translate('xpack.infra.configureSourceActionLabel', { defaultMessage: 'Change source configuration', })} diff --git a/x-pack/plugins/infra/public/pages/metrics/components/invalid_node.tsx b/x-pack/plugins/infra/public/pages/metrics/components/invalid_node.tsx index fde3b61de50b5..43f684cd5a585 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/invalid_node.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/components/invalid_node.tsx @@ -10,10 +10,7 @@ import { identity } from 'fp-ts/lib/function'; import React from 'react'; import { euiStyled } from '../../../../../observability/public'; -import { - ViewSourceConfigurationButton, - ViewSourceConfigurationButtonHrefBase, -} from '../../../components/source_configuration'; +import { ViewSourceConfigurationButton } from '../../../components/source_configuration'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; interface InvalidNodeErrorProps { @@ -59,10 +56,7 @@ export const InvalidNodeError: React.FunctionComponent = - + Date: Tue, 25 Feb 2020 07:18:04 -0600 Subject: [PATCH 049/123] [Uptime] Improve refresh handling when generating test data (#58285) When generating test data we refresh excessively, this can fill up the ES queues and break the tests if we run massive tests. I originally ran into this with https://github.com/elastic/kibana/pull/58078/ which I closed due to finding a better approach. While none of our current tests have the scale to expose this problem, we certainly will add tests that do later, so we should keep this change. Co-authored-by: Elastic Machine --- .../uptime/graphql/helpers/make_checks.ts | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/x-pack/test/api_integration/apis/uptime/graphql/helpers/make_checks.ts b/x-pack/test/api_integration/apis/uptime/graphql/helpers/make_checks.ts index f89905f0da04f..4d3167b14b86f 100644 --- a/x-pack/test/api_integration/apis/uptime/graphql/helpers/make_checks.ts +++ b/x-pack/test/api_integration/apis/uptime/graphql/helpers/make_checks.ts @@ -13,7 +13,8 @@ export const makePing = async ( es: any, monitorId: string, fields: { [key: string]: any }, - mogrify: (doc: any) => any + mogrify: (doc: any) => any, + refresh: boolean = true ) => { const baseDoc = { tcp: { @@ -103,7 +104,7 @@ export const makePing = async ( await es.index({ index: INDEX_NAME, - refresh: true, + refresh, body: doc, }); @@ -115,7 +116,8 @@ export const makeCheck = async ( monitorId: string, numIps: number, fields: { [key: string]: any }, - mogrify: (doc: any) => any + mogrify: (doc: any) => any, + refresh: boolean = true ) => { const cgFields = { monitor: { @@ -137,11 +139,16 @@ export const makeCheck = async ( if (i === numIps - 1) { pingFields.summary = summary; } - const doc = await makePing(es, monitorId, pingFields, mogrify); + const doc = await makePing(es, monitorId, pingFields, mogrify, false); docs.push(doc); // @ts-ignore summary[doc.monitor.status]++; } + + if (refresh) { + es.indices.refresh(); + } + return docs; }; @@ -152,7 +159,8 @@ export const makeChecks = async ( numIps: number, every: number, // number of millis between checks fields: { [key: string]: any } = {}, - mogrify: (doc: any) => any = d => d + mogrify: (doc: any) => any = d => d, + refresh: boolean = true ) => { const checks = []; const oldestTime = new Date().getTime() - numChecks * every; @@ -169,7 +177,11 @@ export const makeChecks = async ( }, }, }); - checks.push(await makeCheck(es, monitorId, numIps, fields, mogrify)); + checks.push(await makeCheck(es, monitorId, numIps, fields, mogrify, false)); + } + + if (refresh) { + es.indices.refresh(); } return checks; @@ -183,19 +195,29 @@ export const makeChecksWithStatus = async ( every: number, fields: { [key: string]: any } = {}, status: 'up' | 'down', - mogrify: (doc: any) => any = d => d + mogrify: (doc: any) => any = d => d, + refresh: boolean = true ) => { const oppositeStatus = status === 'up' ? 'down' : 'up'; - return await makeChecks(es, monitorId, numChecks, numIps, every, fields, d => { - d.monitor.status = status; - if (d.summary) { - d.summary[status] += d.summary[oppositeStatus]; - d.summary[oppositeStatus] = 0; - } - - return mogrify(d); - }); + return await makeChecks( + es, + monitorId, + numChecks, + numIps, + every, + fields, + d => { + d.monitor.status = status; + if (d.summary) { + d.summary[status] += d.summary[oppositeStatus]; + d.summary[oppositeStatus] = 0; + } + + return mogrify(d); + }, + refresh + ); }; // Helper for processing a list of checks to find the time picker bounds. From b756cc3915fe62d405f006fd32bf8678f4c5e402 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 25 Feb 2020 13:39:50 +0000 Subject: [PATCH 050/123] [ML] Adding filebeat config to file dataviz (#58152) * [ML] Adding filebeat config to file dataviz * adding extra help text * removing commented out code * adding extra blank line to processors section * cleaning up types * moving hosts line out of function * typo in config text * updating config based on review * tiny refactor * translating paths text --- .../ml/common/types/file_datavisualizer.ts | 31 +++ .../plugins/ml/public/application/app.tsx | 4 + .../contexts/kibana/kibana_context.ts | 2 + .../filebeat_config_flyout/filebeat_config.ts | 71 +++++++ .../filebeat_config_flyout.tsx | 162 +++++++++++++++ .../filebeat_config_flyout/index.ts | 7 + .../components/import_view/import_view.js | 24 +++ .../import_view/importer/message_importer.js | 5 + .../results_links/{index.js => index.ts} | 0 .../components/results_links/results_links.js | 182 ----------------- .../results_links/results_links.tsx | 190 ++++++++++++++++++ .../application/util/dependency_cache.ts | 10 + x-pack/legacy/plugins/ml/public/legacy.ts | 4 +- x-pack/legacy/plugins/ml/public/plugin.ts | 3 +- .../file_data_visualizer.ts | 27 +-- 15 files changed, 513 insertions(+), 209 deletions(-) create mode 100644 x-pack/legacy/plugins/ml/common/types/file_datavisualizer.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/filebeat_config.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/filebeat_config_flyout.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/index.ts rename x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/{index.js => index.ts} (100%) delete mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/results_links.js create mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/results_links.tsx diff --git a/x-pack/legacy/plugins/ml/common/types/file_datavisualizer.ts b/x-pack/legacy/plugins/ml/common/types/file_datavisualizer.ts new file mode 100644 index 0000000000000..bc03f82673a1f --- /dev/null +++ b/x-pack/legacy/plugins/ml/common/types/file_datavisualizer.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface FindFileStructureResponse { + charset: string; + has_header_row: boolean; + has_byte_order_marker: boolean; + format: string; + field_stats: { + [fieldName: string]: { + count: number; + cardinality: number; + top_hits: Array<{ count: number; value: any }>; + }; + }; + sample_start: string; + num_messages_analyzed: number; + mappings: { + [fieldName: string]: { + type: string; + }; + }; + quote: string; + delimiter: string; + need_client_timezone: boolean; + num_lines_analyzed: number; + column_names: string[]; +} diff --git a/x-pack/legacy/plugins/ml/public/application/app.tsx b/x-pack/legacy/plugins/ml/public/application/app.tsx index 24cbfbfb346dd..add27193deb77 100644 --- a/x-pack/legacy/plugins/ml/public/application/app.tsx +++ b/x-pack/legacy/plugins/ml/public/application/app.tsx @@ -12,6 +12,7 @@ import 'ace'; import { AppMountParameters, CoreStart } from 'kibana/public'; import { DataPublicPluginStart } from 'src/plugins/data/public'; +import { SecurityPluginSetup } from '../../../../../plugins/security/public'; import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; import { setDependencyCache, clearCache } from './util/dependency_cache'; @@ -20,6 +21,7 @@ import { MlRouter } from './routing'; export interface MlDependencies extends AppMountParameters { data: DataPublicPluginStart; + security: SecurityPluginSetup; __LEGACY: { XSRF: string; APP_URL: string; @@ -49,6 +51,7 @@ const App: FC = ({ coreStart, deps }) => { APP_URL: deps.__LEGACY.APP_URL, application: coreStart.application, http: coreStart.http, + security: deps.security, }); deps.onAppLeave(actions => { clearCache(); @@ -64,6 +67,7 @@ const App: FC = ({ coreStart, deps }) => { const services = { appName: 'ML', data: deps.data, + security: deps.security, ...coreStart, }; diff --git a/x-pack/legacy/plugins/ml/public/application/contexts/kibana/kibana_context.ts b/x-pack/legacy/plugins/ml/public/application/contexts/kibana/kibana_context.ts index aaf539322809b..5fcd7c5473d3b 100644 --- a/x-pack/legacy/plugins/ml/public/application/contexts/kibana/kibana_context.ts +++ b/x-pack/legacy/plugins/ml/public/application/contexts/kibana/kibana_context.ts @@ -10,9 +10,11 @@ import { useKibana, KibanaReactContextValue, } from '../../../../../../../../src/plugins/kibana_react/public'; +import { SecurityPluginSetup } from '../../../../../../../plugins/security/public'; interface StartPlugins { data: DataPublicPluginStart; + security: SecurityPluginSetup; } export type StartServices = CoreStart & StartPlugins; // eslint-disable-next-line react-hooks/rules-of-hooks diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/filebeat_config.ts b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/filebeat_config.ts new file mode 100644 index 0000000000000..3344cdf991e6b --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/filebeat_config.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { FindFileStructureResponse } from '../../../../../../common/types/file_datavisualizer'; + +export function createFilebeatConfig( + index: string, + results: FindFileStructureResponse, + ingestPipelineId: string, + username: string | null +) { + return [ + 'filebeat.inputs:', + '- type: log', + ...getPaths(), + ...getEncoding(results), + ...getExcludeLines(results), + ...getMultiline(results), + '', + ...getProcessors(results), + 'output.elasticsearch:', + ' hosts: [""]', + ...getUserDetails(username), + ` index: "${index}"`, + ` pipeline: "${ingestPipelineId}"`, + '', + 'setup:', + ' template.enabled: false', + ' ilm.enabled: false', + ].join('\n'); +} + +function getPaths() { + const txt = i18n.translate('xpack.ml.fileDatavisualizer.fileBeatConfig.paths', { + defaultMessage: 'add path to your files here', + }); + return [' paths:', ` - '<${txt}>'`]; +} + +function getEncoding(results: any) { + return results.charset !== 'UTF-8' ? [` encoding: ${results.charset}`] : []; +} + +function getExcludeLines(results: any) { + return results.exclude_lines_pattern !== undefined + ? [` exclude_lines: ['${results.exclude_lines_pattern.replace(/'/g, "''")}']`] + : []; +} + +function getMultiline(results: any) { + return results.multiline_start_pattern !== undefined + ? [ + ' multiline:', + ` pattern: '${results.multiline_start_pattern.replace(/'/g, "''")}'`, + ' match: after', + ' negate: true', + ] + : []; +} + +function getProcessors(results: any) { + return results.need_client_timezone === true ? ['processors:', '- add_locale: ~', ''] : []; +} + +function getUserDetails(username: string | null) { + return username !== null ? [` username: "${username}"`, ' password: ""'] : []; +} diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/filebeat_config_flyout.tsx b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/filebeat_config_flyout.tsx new file mode 100644 index 0000000000000..30fc74acbabf4 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/filebeat_config_flyout.tsx @@ -0,0 +1,162 @@ +/* + * 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. + */ +/* + * 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, { FC, useState, useEffect } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiFlyout, + EuiFlyoutFooter, + EuiFlexGroup, + EuiFlexItem, + EuiButton, + EuiButtonEmpty, + EuiTitle, + EuiFlyoutBody, + EuiSpacer, + EuiCodeBlock, + EuiCode, + EuiCopy, +} from '@elastic/eui'; +import { createFilebeatConfig } from './filebeat_config'; +import { useMlKibana } from '../../../../contexts/kibana'; +import { FindFileStructureResponse } from '../../../../../../common/types/file_datavisualizer'; + +export enum EDITOR_MODE { + HIDDEN, + READONLY, + EDITABLE, +} +interface Props { + index: string; + results: FindFileStructureResponse; + indexPatternId: string; + ingestPipelineId: string; + closeFlyout(): void; +} +export const FilebeatConfigFlyout: FC = ({ + index, + results, + indexPatternId, + ingestPipelineId, + closeFlyout, +}) => { + const [fileBeatConfig, setFileBeatConfig] = useState(''); + const [username, setUsername] = useState(null); + const { + services: { security }, + } = useMlKibana(); + + useEffect(() => { + security.authc.getCurrentUser().then(user => { + setUsername(user.username === undefined ? null : user.username); + }); + }, []); + + useEffect(() => { + const config = createFilebeatConfig(index, results, ingestPipelineId, username); + setFileBeatConfig(config); + }, [username]); + + return ( + + + + + + + + + + + + + + + + {copy => ( + + + + )} + + + + + + ); +}; + +const Contents: FC<{ + value: string; + index: string; + username: string | null; +}> = ({ value, index, username }) => { + return ( + + +
+ +
+
+ +

+ {index} }} + /> +

+

+ filebeat.yml }} + /> +

+ + + + {value} + + +

+ {username === null ? ( + {''}, + }} + /> + ) : ( + {username}, + password: {''}, + esUrl: {''}, + }} + /> + )} +

+
+ ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/index.ts b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/index.ts new file mode 100644 index 0000000000000..9286b92c2ab97 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/index.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 { FilebeatConfigFlyout } from './filebeat_config_flyout'; diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/import_view.js b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/import_view.js index beb5918e277ae..bdfc27099a185 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/import_view.js +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/import_view.js @@ -20,6 +20,7 @@ import { import { i18n } from '@kbn/i18n'; import { importerFactory } from './importer'; import { ResultsLinks } from '../results_links'; +import { FilebeatConfigFlyout } from '../filebeat_config_flyout'; import { ImportProgress, IMPORT_STATUS } from '../import_progress'; import { ImportErrors } from '../import_errors'; import { ImportSummary } from '../import_summary'; @@ -64,6 +65,7 @@ const DEFAULT_STATE = { indexNameError: '', indexPatternNameError: '', timeFieldName: undefined, + isFilebeatFlyoutVisible: false, }; export class ImportView extends Component { @@ -384,6 +386,16 @@ export class ImportView extends Component { }); }; + showFilebeatFlyout = () => { + this.setState({ isFilebeatFlyoutVisible: true }); + this.props.hideBottomBar(); + }; + + closeFilebeatFlyout = () => { + this.setState({ isFilebeatFlyoutVisible: false }); + this.props.showBottomBar(); + }; + async loadIndexNames() { const indices = await ml.getIndices(); const indexNames = indices.map(i => i.name); @@ -424,6 +436,7 @@ export class ImportView extends Component { indexNameError, indexPatternNameError, timeFieldName, + isFilebeatFlyoutVisible, } = this.state; const createPipeline = pipelineString !== ''; @@ -549,7 +562,18 @@ export class ImportView extends Component { indexPatternId={indexPatternId} timeFieldName={timeFieldName} createIndexPattern={createIndexPattern} + showFilebeatFlyout={this.showFilebeatFlyout} /> + + {isFilebeatFlyoutVisible && ( + + )} )} diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/importer/message_importer.js b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/importer/message_importer.js index 840248817945a..c2d3ac69f0963 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/importer/message_importer.js +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/importer/message_importer.js @@ -77,6 +77,11 @@ export class MessageImporter extends Importer { if (this.multilineStartRegex === null || line.match(this.multilineStartRegex) !== null) { this.addMessage(data, message); message = ''; + } else if (data.length === 0) { + // discard everything before the first line that is considered the first line of a message + // as it could be left over partial data from a spilt or rolled over log, + // or could be a blank line after the header in a csv file + return ''; } else { message += '\n'; } diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/index.js b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/index.js rename to x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/index.ts diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/results_links.js b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/results_links.js deleted file mode 100644 index aaebca2f58963..0000000000000 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/results_links.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { FormattedMessage } from '@kbn/i18n/react'; -import React, { Component } from 'react'; - -import { EuiFlexGroup, EuiFlexItem, EuiCard, EuiIcon } from '@elastic/eui'; - -import moment from 'moment'; - -import { ml } from '../../../../services/ml_api_service'; -import { isFullLicense } from '../../../../license/check_license'; -import { checkPermission } from '../../../../privilege/check_privilege'; -import { mlNodesAvailable } from '../../../../ml_nodes_check/check_ml_nodes'; -import { withKibana } from '../../../../../../../../../../src/plugins/kibana_react/public'; - -const RECHECK_DELAY_MS = 3000; - -class ResultsLinksUI extends Component { - constructor(props) { - super(props); - - this.state = { - from: 'now-30m', - to: 'now', - }; - - this.recheckTimeout = null; - this.showCreateJobLink = true; - } - - componentDidMount() { - this.showCreateJobLink = checkPermission('canCreateJob') && mlNodesAvailable(); - // if this data has a time field, - // find the start and end times - if (this.props.timeFieldName !== undefined) { - this.updateTimeValues(); - } - } - - componentWillUnmount() { - clearTimeout(this.recheckTimeout); - } - - async updateTimeValues(recheck = true) { - const { index, timeFieldName } = this.props; - - const { from, to } = await getFullTimeRange(index, timeFieldName); - this.setState({ - from: from === null ? this.state.from : from, - to: to === null ? this.state.to : to, - }); - - // these links may have been drawn too quickly for the index to be ready - // to give us the correct start and end times. - // especially if the data was small. - // so if the start and end were null, try again in 3s - // the timeout is cleared when this component unmounts. just in case the user - // resets the form or navigates away within 3s - if (recheck && (from === null || to === null)) { - this.recheckTimeout = setTimeout(() => { - this.updateTimeValues(false); - }, RECHECK_DELAY_MS); - } - } - - render() { - const { index, indexPatternId, timeFieldName, createIndexPattern } = this.props; - - const { from, to } = this.state; - - const _g = - this.props.timeFieldName !== undefined - ? `&_g=(time:(from:'${from}',mode:quick,to:'${to}'))` - : ''; - - const { basePath } = this.props.kibana.services.http; - return ( - - {createIndexPattern && ( - - } - title={ - - } - description="" - href={`${basePath.get()}/app/kibana#/discover?&_a=(index:'${indexPatternId}')${_g}`} - /> - - )} - - {isFullLicense() === true && - timeFieldName !== undefined && - this.showCreateJobLink && - createIndexPattern && ( - - } - title={ - - } - description="" - href={`#/jobs/new_job/step/job_type?index=${indexPatternId}${_g}`} - /> - - )} - - {createIndexPattern && ( - - } - title={ - - } - description="" - href={`#/jobs/new_job/datavisualizer?index=${indexPatternId}${_g}`} - /> - - )} - - - } - title={ - - } - description="" - href={`${basePath.get()}/app/kibana#/management/elasticsearch/index_management/indices/filter/${index}`} - /> - - - - } - title={ - - } - description="" - href={`${basePath.get()}/app/kibana#/management/kibana/index_patterns/${ - createIndexPattern ? indexPatternId : '' - }`} - /> - - - ); - } -} - -export const ResultsLinks = withKibana(ResultsLinksUI); - -async function getFullTimeRange(index, timeFieldName) { - const query = { bool: { must: [{ query_string: { analyze_wildcard: true, query: '*' } }] } }; - const resp = await ml.getTimeFieldRange({ - index, - timeFieldName, - query, - }); - - return { - from: moment(resp.start.epoch).toISOString(), - to: moment(resp.end.epoch).toISOString(), - }; -} diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/results_links.tsx b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/results_links.tsx new file mode 100644 index 0000000000000..debadba19051b --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/results_links.tsx @@ -0,0 +1,190 @@ +/* + * 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, { FC, useState, useEffect } from 'react'; +import moment from 'moment'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiFlexGroup, EuiFlexItem, EuiCard, EuiIcon } from '@elastic/eui'; +import { ml } from '../../../../services/ml_api_service'; +import { isFullLicense } from '../../../../license/check_license'; +import { checkPermission } from '../../../../privilege/check_privilege'; +import { mlNodesAvailable } from '../../../../ml_nodes_check/check_ml_nodes'; +import { useMlKibana } from '../../../../contexts/kibana'; + +const RECHECK_DELAY_MS = 3000; + +interface Props { + index: string; + indexPatternId: string; + timeFieldName?: string; + createIndexPattern: boolean; + showFilebeatFlyout(): void; +} + +export const ResultsLinks: FC = ({ + index, + indexPatternId, + timeFieldName, + createIndexPattern, + showFilebeatFlyout, +}) => { + const [duration, setDuration] = useState({ + from: 'now-30m', + to: 'now', + }); + const [showCreateJobLink, setShowCreateJobLink] = useState(false); + const [globalStateString, setGlobalStateString] = useState(''); + const { + services: { + http: { basePath }, + }, + } = useMlKibana(); + + useEffect(() => { + setShowCreateJobLink(checkPermission('canCreateJob') && mlNodesAvailable()); + updateTimeValues(); + }, []); + + useEffect(() => { + const _g = + timeFieldName !== undefined + ? `&_g=(time:(from:'${duration.from}',mode:quick,to:'${duration.to}'))` + : ''; + setGlobalStateString(_g); + }, [duration]); + + async function updateTimeValues(recheck = true) { + if (timeFieldName !== undefined) { + const { from, to } = await getFullTimeRange(index, timeFieldName); + setDuration({ + from: from === null ? duration.from : from, + to: to === null ? duration.to : to, + }); + + // these links may have been drawn too quickly for the index to be ready + // to give us the correct start and end times. + // especially if the data was small. + // so if the start and end were null, try again in 3s + if (recheck && (from === null || to === null)) { + setTimeout(() => { + updateTimeValues(false); + }, RECHECK_DELAY_MS); + } + } + } + + return ( + + {createIndexPattern && ( + + } + title={ + + } + description="" + href={`${basePath.get()}/app/kibana#/discover?&_a=(index:'${indexPatternId}')${globalStateString}`} + /> + + )} + + {isFullLicense() === true && + timeFieldName !== undefined && + showCreateJobLink && + createIndexPattern && ( + + } + title={ + + } + description="" + href={`#/jobs/new_job/step/job_type?index=${indexPatternId}${globalStateString}`} + /> + + )} + + {createIndexPattern && ( + + } + title={ + + } + description="" + href={`#/jobs/new_job/datavisualizer?index=${indexPatternId}${globalStateString}`} + /> + + )} + + + } + title={ + + } + description="" + href={`${basePath.get()}/app/kibana#/management/elasticsearch/index_management/indices/filter/${index}`} + /> + + + + } + title={ + + } + description="" + href={`${basePath.get()}/app/kibana#/management/kibana/index_patterns/${ + createIndexPattern ? indexPatternId : '' + }`} + /> + + + } + title={ + + } + description="" + onClick={showFilebeatFlyout} + /> + + + ); +}; + +async function getFullTimeRange(index: string, timeFieldName: string) { + const query = { bool: { must: [{ query_string: { analyze_wildcard: true, query: '*' } }] } }; + const resp = await ml.getTimeFieldRange({ + index, + timeFieldName, + query, + }); + + return { + from: moment(resp.start.epoch).toISOString(), + to: moment(resp.end.epoch).toISOString(), + }; +} diff --git a/x-pack/legacy/plugins/ml/public/application/util/dependency_cache.ts b/x-pack/legacy/plugins/ml/public/application/util/dependency_cache.ts index 8857485a58644..f837d90dba8fe 100644 --- a/x-pack/legacy/plugins/ml/public/application/util/dependency_cache.ts +++ b/x-pack/legacy/plugins/ml/public/application/util/dependency_cache.ts @@ -20,6 +20,7 @@ import { ChromeRecentlyAccessed, IBasePath, } from 'kibana/public'; +import { SecurityPluginSetup } from '../../../../../../plugins/security/public'; export interface DependencyCache { timefilter: TimefilterSetup | null; @@ -38,6 +39,7 @@ export interface DependencyCache { APP_URL: string | null; application: ApplicationStart | null; http: HttpStart | null; + security: SecurityPluginSetup | null; } const cache: DependencyCache = { @@ -57,6 +59,7 @@ const cache: DependencyCache = { APP_URL: null, application: null, http: null, + security: null, }; export function setDependencyCache(deps: Partial) { @@ -189,6 +192,13 @@ export function getHttp() { return cache.http; } +export function getSecurity() { + if (cache.security === null) { + throw new Error("security hasn't been initialized"); + } + return cache.security; +} + export function clearCache() { console.log('clearing dependency cache'); // eslint-disable-line no-console Object.keys(cache).forEach(k => { diff --git a/x-pack/legacy/plugins/ml/public/legacy.ts b/x-pack/legacy/plugins/ml/public/legacy.ts index bf431f0986d68..40a1afa06b5a6 100644 --- a/x-pack/legacy/plugins/ml/public/legacy.ts +++ b/x-pack/legacy/plugins/ml/public/legacy.ts @@ -6,14 +6,16 @@ import chrome from 'ui/chrome'; import { npSetup, npStart } from 'ui/new_platform'; - import { PluginInitializerContext } from 'src/core/public'; +import { SecurityPluginSetup } from '../../../../plugins/security/public'; + import { plugin } from '.'; const pluginInstance = plugin({} as PluginInitializerContext); export const setup = pluginInstance.setup(npSetup.core, { data: npStart.plugins.data, + security: ((npSetup.plugins as unknown) as { security: SecurityPluginSetup }).security, // security isn't in the PluginsSetup interface, but does exist __LEGACY: { XSRF: chrome.getXsrfToken(), // @ts-ignore getAppUrl is missing from chrome's definition diff --git a/x-pack/legacy/plugins/ml/public/plugin.ts b/x-pack/legacy/plugins/ml/public/plugin.ts index 79af300bce4ec..cb39b31a32b14 100644 --- a/x-pack/legacy/plugins/ml/public/plugin.ts +++ b/x-pack/legacy/plugins/ml/public/plugin.ts @@ -8,7 +8,7 @@ import { Plugin, CoreStart, CoreSetup } from 'src/core/public'; import { MlDependencies } from './application/app'; export class MlPlugin implements Plugin { - setup(core: CoreSetup, { data, __LEGACY }: MlDependencies) { + setup(core: CoreSetup, { data, security, __LEGACY }: MlDependencies) { core.application.register({ id: 'ml', title: 'Machine learning', @@ -21,6 +21,7 @@ export class MlPlugin implements Plugin { onAppLeave: params.onAppLeave, data, __LEGACY, + security, }); }, }); diff --git a/x-pack/legacy/plugins/ml/server/models/file_data_visualizer/file_data_visualizer.ts b/x-pack/legacy/plugins/ml/server/models/file_data_visualizer/file_data_visualizer.ts index fd5b5221393fc..9f30f609c60b6 100644 --- a/x-pack/legacy/plugins/ml/server/models/file_data_visualizer/file_data_visualizer.ts +++ b/x-pack/legacy/plugins/ml/server/models/file_data_visualizer/file_data_visualizer.ts @@ -6,6 +6,7 @@ import Boom from 'boom'; import { RequestHandlerContext } from 'kibana/server'; +import { FindFileStructureResponse } from '../../../common/types/file_datavisualizer'; export type InputData = any[]; @@ -20,31 +21,7 @@ export type FormattedOverrides = InputOverrides & { }; export interface AnalysisResult { - results: { - charset: string; - has_header_row: boolean; - has_byte_order_marker: boolean; - format: string; - field_stats: { - [fieldName: string]: { - count: number; - cardinality: number; - top_hits: Array<{ count: number; value: any }>; - }; - }; - sample_start: string; - num_messages_analyzed: number; - mappings: { - [fieldName: string]: { - type: string; - }; - }; - quote: string; - delimiter: string; - need_client_timezone: boolean; - num_lines_analyzed: number; - column_names: string[]; - }; + results: FindFileStructureResponse; overrides?: FormattedOverrides; } From afb5d8fa5847cdb7e4f7d6d8742a73486815007f Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Tue, 25 Feb 2020 07:43:46 -0600 Subject: [PATCH 051/123] Fix service map popover transaction duration (#58422) It's already microseconds, so not converting it fixes it. Checked services to see if all metrics match now and they do! Fixes #55679 --- .../app/ServiceMap/Popover/ServiceMetricList.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx index 50ce918ea7037..3a6b4c5ebcaac 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx @@ -16,12 +16,7 @@ import { isNumber } from 'lodash'; import React from 'react'; import styled from 'styled-components'; import { ServiceNodeMetrics } from '../../../../../../../../plugins/apm/common/service_map'; -import { - asDuration, - asPercent, - toMicroseconds, - tpmUnit -} from '../../../../utils/formatters'; +import { asDuration, asPercent, tpmUnit } from '../../../../utils/formatters'; function LoadingSpinner() { return ( @@ -70,7 +65,7 @@ export function ServiceMetricList({ } ), description: isNumber(avgTransactionDuration) - ? asDuration(toMicroseconds(avgTransactionDuration, 'milliseconds')) + ? asDuration(avgTransactionDuration) : null }, { From db05fb6738cd906bf231a28d58d5c17d6efe201c Mon Sep 17 00:00:00 2001 From: Vadim Dalecky Date: Tue, 25 Feb 2020 15:00:28 +0100 Subject: [PATCH 052/123] Don't mutate error message (#58452) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 🐛 don't mutate error object in-place This avoids mutating error thrown by an expression function in-place. The error might not even be an object, in which case mutating it will throw. * test: 💍 capture in test that thrown error is not mutated Co-authored-by: Elastic Machine --- src/plugins/expressions/common/execution/execution.test.ts | 1 + src/plugins/expressions/common/execution/execution.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/expressions/common/execution/execution.test.ts b/src/plugins/expressions/common/execution/execution.test.ts index f6ff9efca848b..4776204a8ab2f 100644 --- a/src/plugins/expressions/common/execution/execution.test.ts +++ b/src/plugins/expressions/common/execution/execution.test.ts @@ -630,6 +630,7 @@ describe('Execution', () => { }, }); expect(node2.debug?.rawError).toBeInstanceOf(Error); + expect(node2.debug?.rawError).toEqual(new Error('foo')); }); test('sets .debug object to expected shape', async () => { diff --git a/src/plugins/expressions/common/execution/execution.ts b/src/plugins/expressions/common/execution/execution.ts index 7e7df822724ae..272448870e817 100644 --- a/src/plugins/expressions/common/execution/execution.ts +++ b/src/plugins/expressions/common/execution/execution.ts @@ -230,8 +230,8 @@ export class Execution< input = output; } catch (rawError) { const timeEnd: number = this.params.debug ? performance.now() : 0; - rawError.message = `[${fnName}] > ${rawError.message}`; const error = createError(rawError) as ExpressionValueError; + error.error.message = `[${fnName}] > ${error.error.message}`; if (this.params.debug) { (link as ExpressionAstFunction).debug = { From 418c44a47ed7c5b6807e31aa4be24f4dbc9d6b5b Mon Sep 17 00:00:00 2001 From: patrykkopycinski Date: Tue, 25 Feb 2020 15:00:50 +0100 Subject: [PATCH 053/123] [SIEM] Fix unnecessary re-renders on the Overview page (#56587) --- .../__snapshots__/barchart.test.tsx.snap | 2 - .../components/charts/areachart.test.tsx | 4 +- .../public/components/charts/areachart.tsx | 4 - .../components/charts/barchart.test.tsx | 11 +- .../siem/public/components/charts/common.tsx | 11 +- .../drag_and_drop/draggable_wrapper.tsx | 4 +- .../events_viewer/events_viewer.tsx | 10 +- .../public/components/events_viewer/index.tsx | 18 +- .../siem/public/components/flyout/index.tsx | 55 +++--- .../siem/public/components/inspect/index.tsx | 8 +- .../public/components/navigation/index.tsx | 7 +- .../hosts/authentications_table/index.tsx | 6 +- .../page/hosts/hosts_table/index.tsx | 1 + .../components/page/hosts/kpi_hosts/index.tsx | 1 + .../hosts/uncommon_process_table/index.tsx | 6 +- .../page/network/kpi_network/index.tsx | 1 + .../network/network_dns_table/columns.tsx | 3 +- .../page/network/network_dns_table/index.tsx | 10 +- .../page/network/network_http_table/index.tsx | 6 +- .../network_top_countries_table/index.tsx | 5 +- .../network_top_n_flow_table/index.tsx | 5 +- .../page/network/tls_table/index.tsx | 10 +- .../page/network/users_table/index.tsx | 13 +- .../overview/overview_host_stats/index.tsx | 2 - .../overview/overview_network_stats/index.tsx | 6 +- .../public/components/query_bar/index.tsx | 6 +- .../public/components/search_bar/index.tsx | 6 +- .../source_destination_ip.tsx | 5 +- .../__snapshots__/index.test.tsx.snap | 3 - .../__snapshots__/timeline.test.tsx.snap | 2 +- .../components/timeline/header/index.tsx | 8 +- .../siem/public/components/timeline/index.tsx | 12 +- .../components/timeline/query_bar/index.tsx | 5 +- .../timeline/search_or_filter/index.tsx | 21 ++- .../public/components/timeline/timeline.tsx | 4 - .../public/components/url_state/index.tsx | 4 +- .../components/url_state/use_url_state.tsx | 7 +- .../rules/fetch_index_patterns.tsx | 5 +- .../public/containers/global_time/index.tsx | 18 +- .../containers/query_template_paginated.tsx | 4 +- .../siem/public/containers/source/index.tsx | 1 + .../signals_histogram.tsx | 29 +-- .../rules/components/query_bar/index.tsx | 12 +- .../rules/components/rule_status/index.tsx | 4 +- .../components/step_about_rule/index.tsx | 4 +- .../components/step_define_rule/index.tsx | 13 +- .../components/step_schedule_rule/index.tsx | 4 +- .../pages/hosts/details/details_tabs.tsx | 45 ++--- .../siem/public/pages/hosts/hosts_tabs.tsx | 75 ++++---- .../network/navigation/network_routes.tsx | 171 +++++++++--------- x-pack/legacy/plugins/siem/public/routes.tsx | 8 +- .../siem/public/utils/kql/use_update_kql.tsx | 4 +- .../siem/public/utils/route/spy_routes.tsx | 3 +- x-pack/package.json | 1 + x-pack/tsconfig.json | 2 +- yarn.lock | 9 +- 56 files changed, 374 insertions(+), 330 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/charts/__snapshots__/barchart.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/charts/__snapshots__/barchart.test.tsx.snap index 12b9afb661da1..c330676e9219e 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/__snapshots__/barchart.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/charts/__snapshots__/barchart.test.tsx.snap @@ -1,5 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`BarChartBaseComponent render with customized configs should 2 render BarSeries 1`] = `[Function]`; - exports[`BarChartBaseComponent render with default configs if no customized configs given should 2 render BarSeries 1`] = `[Function]`; diff --git a/x-pack/legacy/plugins/siem/public/components/charts/areachart.test.tsx b/x-pack/legacy/plugins/siem/public/components/charts/areachart.test.tsx index 27f0222b96b77..3c2de28ae423c 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/areachart.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/areachart.test.tsx @@ -331,7 +331,7 @@ describe('AreaChart', () => { }); it(`should render area chart`, () => { - expect(shallowWrapper.find('WrappedByAutoSizer')).toHaveLength(1); + expect(shallowWrapper.find('AreaChartBase')).toHaveLength(1); expect(shallowWrapper.find('ChartPlaceHolder')).toHaveLength(0); }); }); @@ -344,7 +344,7 @@ describe('AreaChart', () => { }); it(`should render a chart place holder`, () => { - expect(shallowWrapper.find('WrappedByAutoSizer')).toHaveLength(0); + expect(shallowWrapper.find('AreaChartBase')).toHaveLength(0); expect(shallowWrapper.find('ChartPlaceHolder')).toHaveLength(1); }); } diff --git a/x-pack/legacy/plugins/siem/public/components/charts/areachart.tsx b/x-pack/legacy/plugins/siem/public/components/charts/areachart.tsx index b66cc77e30aad..f3b2b736ed87d 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/areachart.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/areachart.tsx @@ -146,8 +146,4 @@ export const AreaChartComponent: React.FC = ({ areaChar ); }; -AreaChartComponent.displayName = 'AreaChartComponent'; - export const AreaChart = React.memo(AreaChartComponent); - -AreaChart.displayName = 'AreaChart'; diff --git a/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx b/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx index 0b6635b04d380..272c41833f368 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/barchart.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { BarChartBaseComponent, BarChartComponent } from './barchart'; import { ChartSeriesData } from './common'; -import { BarSeries, ScaleType, Axis } from '@elastic/charts'; +import { Chart, BarSeries, Axis, ScaleType } from '@elastic/charts'; jest.mock('../../lib/kibana'); @@ -139,7 +139,7 @@ describe('BarChartBaseComponent', () => { }); it('should render two bar series', () => { - expect(shallowWrapper.find('Chart')).toHaveLength(1); + expect(shallowWrapper.find(Chart)).toHaveLength(1); }); }); @@ -167,7 +167,6 @@ describe('BarChartBaseComponent', () => { }); it(`should ${mockBarChartData.length} render BarSeries`, () => { - expect(shallow).toMatchSnapshot(); expect(shallowWrapper.find(BarSeries)).toHaveLength(mockBarChartData.length); }); @@ -265,7 +264,7 @@ describe('BarChartBaseComponent', () => { }); it('should not render without height and width', () => { - expect(shallowWrapper.find('Chart')).toHaveLength(0); + expect(shallowWrapper.find(Chart)).toHaveLength(0); }); }); }); @@ -278,7 +277,7 @@ describe.each(chartDataSets)('BarChart with valid data [%o]', data => { }); it(`should render chart`, () => { - expect(shallowWrapper.find('WrappedByAutoSizer')).toHaveLength(1); + expect(shallowWrapper.find('BarChartBase')).toHaveLength(1); expect(shallowWrapper.find('ChartPlaceHolder')).toHaveLength(0); }); }); @@ -291,7 +290,7 @@ describe.each(chartHolderDataSets)('BarChart with invalid data [%o]', data => { }); it(`should render a ChartPlaceHolder`, () => { - expect(shallowWrapper.find('WrappedByAutoSizer')).toHaveLength(0); + expect(shallowWrapper.find('BarChartBase')).toHaveLength(0); expect(shallowWrapper.find('ChartPlaceHolder')).toHaveLength(1); }); }); diff --git a/x-pack/legacy/plugins/siem/public/components/charts/common.tsx b/x-pack/legacy/plugins/siem/public/components/charts/common.tsx index 03b412f575646..7377bcbe7050f 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/common.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/common.tsx @@ -16,7 +16,9 @@ import { TickFormatter, Position, } from '@elastic/charts'; +import React, { useMemo } from 'react'; import styled from 'styled-components'; + import { useUiSetting } from '../../lib/kibana'; import { DEFAULT_DARK_MODE } from '../../../common/constants'; @@ -54,7 +56,7 @@ export interface ChartSeriesData { color?: string | undefined; } -export const WrappedByAutoSizer = styled.div<{ height?: string }>` +const WrappedByAutoSizerComponent = styled.div<{ height?: string }>` ${style => ` height: ${style.height != null ? style.height : defaultChartHeight}; @@ -66,7 +68,9 @@ export const WrappedByAutoSizer = styled.div<{ height?: string }>` } `; -WrappedByAutoSizer.displayName = 'WrappedByAutoSizer'; +WrappedByAutoSizerComponent.displayName = 'WrappedByAutoSizer'; + +export const WrappedByAutoSizer = React.memo(WrappedByAutoSizerComponent); export enum SeriesType { BAR = 'bar', @@ -96,8 +100,9 @@ const theme: PartialTheme = { export const useTheme = () => { const isDarkMode = useUiSetting(DEFAULT_DARK_MODE); const defaultTheme = isDarkMode ? DARK_THEME : LIGHT_THEME; + const themeValue = useMemo(() => mergeWithDefaultTheme(theme, defaultTheme), []); - return mergeWithDefaultTheme(theme, defaultTheme); + return themeValue; }; export const chartDefaultSettings = { diff --git a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.tsx b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.tsx index cf958bfd75d3b..7d84403b87f8d 100644 --- a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.tsx +++ b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEqual } from 'lodash/fp'; import React, { createContext, useContext, useEffect } from 'react'; import { Draggable, @@ -14,6 +13,7 @@ import { } from 'react-beautiful-dnd'; import { connect, ConnectedProps } from 'react-redux'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal'; import { EuiPortal } from '@elastic/eui'; import { dragAndDropActions } from '../../store/drag_and_drop'; @@ -122,7 +122,7 @@ const DraggableWrapperComponent = React.memo( }, (prevProps, nextProps) => { return ( - isEqual(prevProps.dataProvider, nextProps.dataProvider) && + deepEqual(prevProps.dataProvider, nextProps.dataProvider) && prevProps.render !== nextProps.render && prevProps.truncate === nextProps.truncate ); diff --git a/x-pack/legacy/plugins/siem/public/components/events_viewer/events_viewer.tsx b/x-pack/legacy/plugins/siem/public/components/events_viewer/events_viewer.tsx index 2a4d08ea214bc..a913186d9ad3b 100644 --- a/x-pack/legacy/plugins/siem/public/components/events_viewer/events_viewer.tsx +++ b/x-pack/legacy/plugins/siem/public/components/events_viewer/events_viewer.tsx @@ -5,10 +5,10 @@ */ import { EuiPanel } from '@elastic/eui'; -import deepEqual from 'fast-deep-equal'; -import { getOr, isEmpty, isEqual, union } from 'lodash/fp'; +import { getOr, isEmpty, union } from 'lodash/fp'; import React, { useMemo } from 'react'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal'; import useResizeObserver from 'use-resize-observer/polyfilled'; import { BrowserFields } from '../../containers/source'; @@ -228,7 +228,7 @@ const EventsViewerComponent: React.FC = ({ export const EventsViewer = React.memo( EventsViewerComponent, (prevProps, nextProps) => - isEqual(prevProps.browserFields, nextProps.browserFields) && + deepEqual(prevProps.browserFields, nextProps.browserFields) && prevProps.columns === nextProps.columns && prevProps.dataProviders === nextProps.dataProviders && prevProps.deletedEventIds === nextProps.deletedEventIds && @@ -241,9 +241,9 @@ export const EventsViewer = React.memo( prevProps.itemsPerPage === nextProps.itemsPerPage && prevProps.itemsPerPageOptions === nextProps.itemsPerPageOptions && prevProps.kqlMode === nextProps.kqlMode && - isEqual(prevProps.query, nextProps.query) && + deepEqual(prevProps.query, nextProps.query) && prevProps.start === nextProps.start && prevProps.sort === nextProps.sort && - isEqual(prevProps.timelineTypeContext, nextProps.timelineTypeContext) && + deepEqual(prevProps.timelineTypeContext, nextProps.timelineTypeContext) && prevProps.utilityBar === nextProps.utilityBar ); diff --git a/x-pack/legacy/plugins/siem/public/components/events_viewer/index.tsx b/x-pack/legacy/plugins/siem/public/components/events_viewer/index.tsx index 762ae8497dadb..9b31be40dd955 100644 --- a/x-pack/legacy/plugins/siem/public/components/events_viewer/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/events_viewer/index.tsx @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEqual } from 'lodash/fp'; import React, { useCallback, useMemo, useEffect } from 'react'; import { connect, ConnectedProps } from 'react-redux'; +import deepEqual from 'fast-deep-equal'; import { inputsModel, inputsSelectors, State, timelineSelectors } from '../../store'; import { inputsActions, timelineActions } from '../../store/actions'; @@ -197,23 +197,23 @@ export const StatefulEventsViewer = connector( StatefulEventsViewerComponent, (prevProps, nextProps) => prevProps.id === nextProps.id && - isEqual(prevProps.columns, nextProps.columns) && - isEqual(prevProps.dataProviders, nextProps.dataProviders) && + deepEqual(prevProps.columns, nextProps.columns) && + deepEqual(prevProps.dataProviders, nextProps.dataProviders) && prevProps.deletedEventIds === nextProps.deletedEventIds && prevProps.end === nextProps.end && - isEqual(prevProps.filters, nextProps.filters) && + deepEqual(prevProps.filters, nextProps.filters) && prevProps.isLive === nextProps.isLive && prevProps.itemsPerPage === nextProps.itemsPerPage && - isEqual(prevProps.itemsPerPageOptions, nextProps.itemsPerPageOptions) && + deepEqual(prevProps.itemsPerPageOptions, nextProps.itemsPerPageOptions) && prevProps.kqlMode === nextProps.kqlMode && - isEqual(prevProps.query, nextProps.query) && - isEqual(prevProps.sort, nextProps.sort) && + deepEqual(prevProps.query, nextProps.query) && + deepEqual(prevProps.sort, nextProps.sort) && prevProps.start === nextProps.start && - isEqual(prevProps.pageFilters, nextProps.pageFilters) && + deepEqual(prevProps.pageFilters, nextProps.pageFilters) && prevProps.showCheckboxes === nextProps.showCheckboxes && prevProps.showRowRenderers === nextProps.showRowRenderers && prevProps.start === nextProps.start && - isEqual(prevProps.timelineTypeContext, nextProps.timelineTypeContext) && + deepEqual(prevProps.timelineTypeContext, nextProps.timelineTypeContext) && prevProps.utilityBar === nextProps.utilityBar ) ); diff --git a/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx b/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx index eb41773bb21c8..22fc9f27ce26c 100644 --- a/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx @@ -6,7 +6,7 @@ import { EuiBadge } from '@elastic/eui'; import { defaultTo, getOr } from 'lodash/fp'; -import React from 'react'; +import React, { useCallback } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import styled from 'styled-components'; @@ -58,28 +58,39 @@ export const FlyoutComponent = React.memo( timelineId, usersViewing, width, - }) => ( - <> - - showTimeline({ id: timelineId, show: false })} + }) => { + const handleClose = useCallback(() => showTimeline({ id: timelineId, show: false }), [ + showTimeline, + timelineId, + ]); + const handleOpen = useCallback(() => showTimeline({ id: timelineId, show: true }), [ + showTimeline, + timelineId, + ]); + + return ( + <> + + + {children} + + + - {children} - - - showTimeline({ id: timelineId, show: true })} - /> - - ) + onOpen={handleOpen} + /> + + ); + } ); FlyoutComponent.displayName = 'FlyoutComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx b/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx index 405a8f060948e..d6f8143745356 100644 --- a/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx @@ -5,7 +5,7 @@ */ import { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; -import { getOr } from 'lodash/fp'; +import { getOr, omit } from 'lodash/fp'; import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; @@ -162,7 +162,11 @@ const makeMapStateToProps = () => { const getGlobalQuery = inputsSelectors.globalQueryByIdSelector(); const getTimelineQuery = inputsSelectors.timelineQueryByIdSelector(); const mapStateToProps = (state: State, { inputId = 'global', queryId }: OwnProps) => { - return inputId === 'global' ? getGlobalQuery(state, queryId) : getTimelineQuery(state, queryId); + const props = + inputId === 'global' ? getGlobalQuery(state, queryId) : getTimelineQuery(state, queryId); + // refetch caused unnecessary component rerender and it was even not used + const propsWithoutRefetch = omit('refetch', props); + return propsWithoutRefetch; }; return mapStateToProps; }; diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/index.tsx b/x-pack/legacy/plugins/siem/public/components/navigation/index.tsx index e40cc887ab5ff..8a754cb47475f 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/navigation/index.tsx @@ -4,11 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import isEqual from 'lodash/fp/isEqual'; -import deepEqual from 'fast-deep-equal'; import React, { useEffect } from 'react'; import { connect } from 'react-redux'; import { compose } from 'redux'; +import deepEqual from 'fast-deep-equal'; import { useKibana } from '../../lib/kibana'; import { RouteSpyState } from '../../utils/route/types'; @@ -81,8 +80,8 @@ export const SiemNavigationRedux = compose< (prevProps, nextProps) => prevProps.pathName === nextProps.pathName && prevProps.search === nextProps.search && - isEqual(prevProps.navTabs, nextProps.navTabs) && - isEqual(prevProps.urlState, nextProps.urlState) && + deepEqual(prevProps.navTabs, nextProps.navTabs) && + deepEqual(prevProps.urlState, nextProps.urlState) && deepEqual(prevProps.state, nextProps.state) ) ); diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx index 853ba7ae23414..678faff7654db 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx @@ -7,7 +7,7 @@ /* eslint-disable react/display-name */ import { has } from 'lodash/fp'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { hostsActions } from '../../../../store/hosts'; @@ -100,10 +100,12 @@ const AuthenticationTableComponent = React.memo( [type, updateTableActivePage] ); + const columns = useMemo(() => getAuthenticationColumnsCurated(type), [type]); + return ( ( [type, updateTableActivePage] ); + const columns = useMemo(() => getUncommonColumnsCurated(type), [type]); + return ( ]; -export const getNetworkDnsColumns = (type: networkModel.NetworkType): NetworkDnsColumns => [ +export const getNetworkDnsColumns = (): NetworkDnsColumns => [ { field: `node.${NetworkDnsFields.dnsName}`, name: i18n.REGISTERED_DOMAIN, diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx index f3fe98936a55d..c1dd96c5c96f9 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.tsx @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEqual } from 'lodash/fp'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { connect, ConnectedProps } from 'react-redux'; +import deepEqual from 'fast-deep-equal'; import { networkActions } from '../../../../store/actions'; import { @@ -93,7 +93,7 @@ export const NetworkDnsTableComponent = React.memo( field: criteria.sort.field.split('.')[1] as NetworkDnsFields, direction: criteria.sort.direction as Direction, }; - if (!isEqual(newDnsSortField, sort)) { + if (!deepEqual(newDnsSortField, sort)) { updateNetworkTable({ networkType: type, tableType, @@ -115,10 +115,12 @@ export const NetworkDnsTableComponent = React.memo( [type, updateNetworkTable, isPtrIncluded] ); + const columns = useMemo(() => getNetworkDnsColumns(), []); + return ( = ({ const sorting = { field: `node.${NetworkHttpFields.requestCount}`, direction: sort.direction }; + const columns = useMemo(() => getNetworkHttpColumns(tableType), [tableType]); + return ( = ({ field: field as NetworkTopTablesFields, direction: newSortDirection as Direction, }; - if (!isEqual(newTopNFlowSort, sort)) { + if (!deepEqual(newTopNFlowSort, sort)) { updateNetworkTable({ networkType: type, tableType, diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx index 77abae68b76bf..d1512699cc709 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEqual } from 'lodash/fp'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { connect, ConnectedProps } from 'react-redux'; +import deepEqual from 'fast-deep-equal'; import { networkActions } from '../../../../store/network'; import { TlsEdges, TlsSortField, TlsFields, Direction } from '../../../../graphql/types'; @@ -91,7 +91,7 @@ const TlsTableComponent = React.memo( field: getSortFromString(splitField[splitField.length - 1]), direction: criteria.sort.direction as Direction, }; - if (!isEqual(newTlsSort, sort)) { + if (!deepEqual(newTlsSort, sort)) { updateNetworkTable({ networkType: type, tableType, @@ -103,10 +103,12 @@ const TlsTableComponent = React.memo( [sort, type, tableType, updateNetworkTable] ); + const columns = useMemo(() => getTlsColumns(tlsTableId), [tlsTableId]); + return ( ( field: getSortFromString(splitField[splitField.length - 1]), direction: criteria.sort.direction as Direction, }; - if (!isEqual(newUsersSort, sort)) { + if (!deepEqual(newUsersSort, sort)) { updateNetworkTable({ networkType: type, tableType, @@ -109,10 +109,15 @@ const UsersTableComponent = React.memo( [sort, type, updateNetworkTable] ); + const columns = useMemo(() => getUsersColumns(flowTarget, usersTableId), [ + flowTarget, + usersTableId, + ]); + return ( = ({ data, loading ); }; -OverviewHostStatsComponent.displayName = 'OverviewHostStatsComponent'; - export const OverviewHostStats = React.memo(OverviewHostStatsComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network_stats/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network_stats/index.tsx index 260b1d6895140..ca947c29bc382 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network_stats/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network_stats/index.tsx @@ -130,7 +130,7 @@ const AccordionContent = styled.div` margin-top: 8px; `; -export const OverviewNetworkStats = React.memo(({ data, loading }) => { +const OverviewNetworkStatsComponent: React.FC = ({ data, loading }) => { const allNetworkStats = getOverviewNetworkStats(data); const allNetworkStatsCount = allNetworkStats.reduce((total, stat) => total + stat.count, 0); @@ -190,6 +190,6 @@ export const OverviewNetworkStats = React.memo(({ data, lo })} ); -}); +}; -OverviewNetworkStats.displayName = 'OverviewNetworkStats'; +export const OverviewNetworkStats = React.memo(OverviewNetworkStatsComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/query_bar/index.tsx b/x-pack/legacy/plugins/siem/public/components/query_bar/index.tsx index 03a8143c89517..557d389aefee9 100644 --- a/x-pack/legacy/plugins/siem/public/components/query_bar/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/query_bar/index.tsx @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEqual } from 'lodash/fp'; import React, { memo, useState, useEffect, useMemo, useCallback } from 'react'; +import deepEqual from 'fast-deep-equal'; import { Filter, @@ -64,7 +64,7 @@ export const QueryBar = memo( const onQuerySubmit = useCallback( (payload: { dateRange: TimeRange; query?: Query }) => { - if (payload.query != null && !isEqual(payload.query, filterQuery)) { + if (payload.query != null && !deepEqual(payload.query, filterQuery)) { onSubmitQuery(payload.query); } }, @@ -73,7 +73,7 @@ export const QueryBar = memo( const onQueryChange = useCallback( (payload: { dateRange: TimeRange; query?: Query }) => { - if (payload.query != null && !isEqual(payload.query, draftQuery)) { + if (payload.query != null && !deepEqual(payload.query, draftQuery)) { setDraftQuery(payload.query); onChangedQuery(payload.query); } diff --git a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx index cb5729ad8e26e..2513004af84dd 100644 --- a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx @@ -4,12 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getOr, isEqual, set } from 'lodash/fp'; +import { getOr, set } from 'lodash/fp'; import React, { memo, useEffect, useCallback, useMemo } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; import { Subscription } from 'rxjs'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal'; import { FilterManager, IIndexPattern, TimeRange, Query, Filter } from 'src/plugins/data/public'; import { SavedQuery } from 'src/legacy/core_plugins/data/public'; @@ -60,7 +61,6 @@ const SearchBarComponent = memo( setSavedQuery, setSearchBarFilter, start, - timelineId, toStr, updateSearch, dataTestSubj, @@ -108,7 +108,7 @@ const SearchBarComponent = memo( updateSearchBar.start = payload.dateRange.from; } - if (payload.query != null && !isEqual(payload.query, filterQuery)) { + if (payload.query != null && !deepEqual(payload.query, filterQuery)) { isStateUpdated = true; updateSearchBar = set('query', payload.query, updateSearchBar); } diff --git a/x-pack/legacy/plugins/siem/public/components/source_destination/source_destination_ip.tsx b/x-pack/legacy/plugins/siem/public/components/source_destination/source_destination_ip.tsx index 33159387214e4..b8192cce11e5a 100644 --- a/x-pack/legacy/plugins/siem/public/components/source_destination/source_destination_ip.tsx +++ b/x-pack/legacy/plugins/siem/public/components/source_destination/source_destination_ip.tsx @@ -5,8 +5,9 @@ */ import { EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { isEmpty, isEqual, uniqWith } from 'lodash/fp'; +import { isEmpty, uniqWith } from 'lodash/fp'; import React from 'react'; +import deepEqual from 'fast-deep-equal'; import { DESTINATION_IP_FIELD_NAME, SOURCE_IP_FIELD_NAME } from '../ip'; import { DESTINATION_PORT_FIELD_NAME, SOURCE_PORT_FIELD_NAME, Port } from '../port'; @@ -115,7 +116,7 @@ const IpAdressesWithPorts = React.memo<{ return ( - {uniqWith(isEqual, ipPortPairs).map( + {uniqWith(deepEqual, ipPortPairs).map( ipPortPair => ipPortPair.ip != null && ( diff --git a/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap index 69596ba8f3325..ef077ece19f92 100644 --- a/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap @@ -94,7 +94,6 @@ exports[`Stat Items Component disable charts it renders the default widget 1`] = isInspected={false} loading={false} queryId="statItems" - refetch={null} selectedInspectIndex={0} setIsInspected={[Function]} title="KPI HOSTS" @@ -328,7 +327,6 @@ exports[`Stat Items Component disable charts it renders the default widget 2`] = isInspected={false} loading={false} queryId="statItems" - refetch={null} selectedInspectIndex={0} setIsInspected={[Function]} title="KPI HOSTS" @@ -632,7 +630,6 @@ exports[`Stat Items Component rendering kpis with charts it renders the default isInspected={false} loading={false} queryId="statItems" - refetch={null} selectedInspectIndex={0} setIsInspected={[Function]} title="KPI UNIQUE_PRIVATE_IPS" diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/__snapshots__/timeline.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/timeline/__snapshots__/timeline.test.tsx.snap index 3fcd258b79147..372930ee3167d 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/__snapshots__/timeline.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/timeline/__snapshots__/timeline.test.tsx.snap @@ -8,7 +8,7 @@ exports[`Timeline rendering renders correctly against snapshot 1`] = ` justifyContent="flexStart" > - = ({ browserFields, id, indexPattern, @@ -60,7 +60,7 @@ export const TimelineHeaderComponent = ({ onToggleDataProviderExcluded, show, showCallOutUnauthorizedMsg, -}: Props) => ( +}) => ( {showCallOutUnauthorizedMsg && ( ); -TimelineHeaderComponent.displayName = 'TimelineHeaderComponent'; - export const TimelineHeader = React.memo(TimelineHeaderComponent); - -TimelineHeader.displayName = 'TimelineHeader'; diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx index d782d0366f041..0ce6bc16f1325 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEqual } from 'lodash/fp'; import React, { useEffect, useCallback, useMemo } from 'react'; import { connect, ConnectedProps } from 'react-redux'; +import deepEqual from 'fast-deep-equal'; import { WithSource } from '../../containers/source'; import { useSignalIndex } from '../../containers/detection_engine/signals/use_signal_index'; @@ -215,11 +215,11 @@ const StatefulTimelineComponent = React.memo( prevProps.show === nextProps.show && prevProps.showCallOutUnauthorizedMsg === nextProps.showCallOutUnauthorizedMsg && prevProps.start === nextProps.start && - isEqual(prevProps.columns, nextProps.columns) && - isEqual(prevProps.dataProviders, nextProps.dataProviders) && - isEqual(prevProps.filters, nextProps.filters) && - isEqual(prevProps.itemsPerPageOptions, nextProps.itemsPerPageOptions) && - isEqual(prevProps.sort, nextProps.sort) + deepEqual(prevProps.columns, nextProps.columns) && + deepEqual(prevProps.dataProviders, nextProps.dataProviders) && + deepEqual(prevProps.filters, nextProps.filters) && + deepEqual(prevProps.itemsPerPageOptions, nextProps.itemsPerPageOptions) && + deepEqual(prevProps.sort, nextProps.sort) ); } ); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/query_bar/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/query_bar/index.tsx index 96b8df6d8ada7..7f662cdb2f1b4 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/query_bar/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/query_bar/index.tsx @@ -4,9 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEqual, isEmpty } from 'lodash/fp'; +import { isEmpty } from 'lodash/fp'; import React, { memo, useCallback, useState, useEffect } from 'react'; import { Subscription } from 'rxjs'; +import deepEqual from 'fast-deep-equal'; import { IIndexPattern, @@ -127,7 +128,7 @@ export const QueryBarTimeline = memo( const filterWithoutDropArea = filterManager .getFilters() .filter((f: Filter) => f.meta.controlledBy !== timelineFilterDropArea); - if (!isEqual(filters, filterWithoutDropArea)) { + if (!deepEqual(filters, filterWithoutDropArea)) { filterManager.setFilters(filters); } }, [filters]); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/search_or_filter/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/search_or_filter/index.tsx index d1904fd5d9aac..87061bdbb5d02 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/search_or_filter/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/search_or_filter/index.tsx @@ -4,10 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getOr, isEqual } from 'lodash/fp'; +import { getOr } from 'lodash/fp'; import React, { useCallback } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; +import deepEqual from 'fast-deep-equal'; import { Filter, IIndexPattern } from '../../../../../../../../src/plugins/data/public'; import { BrowserFields } from '../../../containers/source'; @@ -152,15 +153,15 @@ const StatefulSearchOrFilterComponent = React.memo( prevProps.isRefreshPaused === nextProps.isRefreshPaused && prevProps.refreshInterval === nextProps.refreshInterval && prevProps.timelineId === nextProps.timelineId && - isEqual(prevProps.browserFields, nextProps.browserFields) && - isEqual(prevProps.dataProviders, nextProps.dataProviders) && - isEqual(prevProps.filters, nextProps.filters) && - isEqual(prevProps.filterQuery, nextProps.filterQuery) && - isEqual(prevProps.filterQueryDraft, nextProps.filterQueryDraft) && - isEqual(prevProps.indexPattern, nextProps.indexPattern) && - isEqual(prevProps.kqlMode, nextProps.kqlMode) && - isEqual(prevProps.savedQueryId, nextProps.savedQueryId) && - isEqual(prevProps.timelineId, nextProps.timelineId) + deepEqual(prevProps.browserFields, nextProps.browserFields) && + deepEqual(prevProps.dataProviders, nextProps.dataProviders) && + deepEqual(prevProps.filters, nextProps.filters) && + deepEqual(prevProps.filterQuery, nextProps.filterQuery) && + deepEqual(prevProps.filterQueryDraft, nextProps.filterQueryDraft) && + deepEqual(prevProps.indexPattern, nextProps.indexPattern) && + deepEqual(prevProps.kqlMode, nextProps.kqlMode) && + deepEqual(prevProps.savedQueryId, nextProps.savedQueryId) && + deepEqual(prevProps.timelineId, nextProps.timelineId) ); } ); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx index c9ff0296a40e2..58bbbef328ddf 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx @@ -229,8 +229,4 @@ export const TimelineComponent: React.FC = ({ ); }; -TimelineComponent.displayName = 'TimelineComponent'; - export const Timeline = React.memo(TimelineComponent); - -Timeline.displayName = 'Timeline'; diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx index e656ec3496d8d..294e41a1faa7b 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEqual } from 'lodash/fp'; import React from 'react'; import { compose, Dispatch } from 'redux'; import { connect } from 'react-redux'; +import deepEqual from 'fast-deep-equal'; import { timelineActions } from '../../store/actions'; import { RouteSpyState } from '../../utils/route/types'; @@ -39,7 +39,7 @@ export const UrlStateRedux = compose - prevProps.pathName === nextProps.pathName && isEqual(prevProps.urlState, nextProps.urlState) + prevProps.pathName === nextProps.pathName && deepEqual(prevProps.urlState, nextProps.urlState) ) ); diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx index deaf9bbf5011d..a7704e0e86970 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx +++ b/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx @@ -4,8 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEqual, difference, isEmpty } from 'lodash/fp'; +import { difference, isEmpty } from 'lodash/fp'; import { useEffect, useRef, useState } from 'react'; +import deepEqual from 'fast-deep-equal'; import { useKibana } from '../../lib/kibana'; import { useApolloClient } from '../../utils/apollo_context'; @@ -77,7 +78,7 @@ export const useUrlStateHooks = ({ const updatedUrlStateString = getParamFromQueryString(getQueryStringFromLocation(mySearch), urlKey) ?? newUrlStateString; - if (isInitializing || !isEqual(updatedUrlStateString, newUrlStateString)) { + if (isInitializing || !deepEqual(updatedUrlStateString, newUrlStateString)) { urlStateToUpdate = [ ...urlStateToUpdate, { @@ -157,7 +158,7 @@ export const useUrlStateHooks = ({ if (isInitializing && pageName != null && pageName !== '') { handleInitialize(type); setIsInitializing(false); - } else if (!isEqual(urlState, prevProps.urlState) && !isInitializing) { + } else if (!deepEqual(urlState, prevProps.urlState) && !isInitializing) { let mySearch = search; URL_STATE_KEYS[type].forEach((urlKey: KeyUrlState) => { if ( diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/fetch_index_patterns.tsx b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/fetch_index_patterns.tsx index b7ad41b8ba1bb..06c4d1054bca4 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/fetch_index_patterns.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/fetch_index_patterns.tsx @@ -4,8 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEmpty, isEqual, get } from 'lodash/fp'; +import { isEmpty, get } from 'lodash/fp'; import { useEffect, useState, Dispatch, SetStateAction } from 'react'; +import deepEqual from 'fast-deep-equal'; import { IIndexPattern } from '../../../../../../../../src/plugins/data/public'; import { @@ -41,7 +42,7 @@ export const useFetchIndexPatterns = (defaultIndices: string[] = []): Return => const [, dispatchToaster] = useStateToaster(); useEffect(() => { - if (!isEqual(defaultIndices, indices)) { + if (!deepEqual(defaultIndices, indices)) { setIndices(defaultIndices); } }, [defaultIndices, indices]); diff --git a/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx b/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx index caf597d02c835..4632e9aee3fdd 100644 --- a/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState, useEffect } from 'react'; +import React, { useCallback, useState, useEffect } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { inputsModel, inputsSelectors, State } from '../../store'; @@ -41,6 +41,17 @@ export const GlobalTimeComponent: React.FC = ({ }) => { const [isInitializing, setIsInitializing] = useState(true); + const setQuery = useCallback( + ({ id, inspect, loading, refetch }: SetQuery) => + setGlobalQuery({ inputId: 'global', id, inspect, loading, refetch }), + [setGlobalQuery] + ); + + const deleteQuery = useCallback( + ({ id }: { id: string }) => deleteOneQuery({ inputId: 'global', id }), + [deleteOneQuery] + ); + useEffect(() => { if (isInitializing) { setIsInitializing(false); @@ -56,9 +67,8 @@ export const GlobalTimeComponent: React.FC = ({ isInitializing, from, to, - setQuery: ({ id, inspect, loading, refetch }: SetQuery) => - setGlobalQuery({ inputId: 'global', id, inspect, loading, refetch }), - deleteQuery: ({ id }: { id: string }) => deleteOneQuery({ inputId: 'global', id }), + setQuery, + deleteQuery, })} ); diff --git a/x-pack/legacy/plugins/siem/public/containers/query_template_paginated.tsx b/x-pack/legacy/plugins/siem/public/containers/query_template_paginated.tsx index 4d6ab757fdea7..db618f216d83e 100644 --- a/x-pack/legacy/plugins/siem/public/containers/query_template_paginated.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/query_template_paginated.tsx @@ -5,10 +5,10 @@ */ import { ApolloQueryResult, NetworkStatus } from 'apollo-client'; -import { isEqual } from 'lodash/fp'; import memoizeOne from 'memoize-one'; import React from 'react'; import { FetchMoreOptions, FetchMoreQueryOptions, OperationVariables } from 'react-apollo'; +import deepEqual from 'fast-deep-equal'; import { ESQuery } from '../../common/typed_json'; import { inputsModel } from '../store/model'; @@ -85,7 +85,7 @@ export class QueryTemplatePaginated< public isItAValidLoading(loading: boolean, variables: TVariables, networkStatus: NetworkStatus) { if ( !this.myLoading && - (!isEqual(variables, this.queryVariables) || networkStatus === NetworkStatus.refetch) && + (!deepEqual(variables, this.queryVariables) || networkStatus === NetworkStatus.refetch) && loading ) { this.myLoading = true; diff --git a/x-pack/legacy/plugins/siem/public/containers/source/index.tsx b/x-pack/legacy/plugins/siem/public/containers/source/index.tsx index 0336e4a9a977b..e454421ca955d 100644 --- a/x-pack/legacy/plugins/siem/public/containers/source/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/source/index.tsx @@ -10,6 +10,7 @@ import { Query } from 'react-apollo'; import React, { useEffect, useMemo, useState } from 'react'; import memoizeOne from 'memoize-one'; import { IIndexPattern } from 'src/plugins/data/public'; + import { useUiSetting$ } from '../../lib/kibana'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram.tsx index 92f6740e4d767..2d9b1ee844b4b 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram.tsx @@ -12,9 +12,11 @@ import { HistogramBarSeries, Position, Settings, + ChartSizeArray, } from '@elastic/charts'; -import React from 'react'; +import React, { useMemo } from 'react'; import { EuiProgress } from '@elastic/eui'; + import { useTheme } from '../../../../components/charts/common'; import { histogramDateTimeFormatter } from '../../../../components/utils'; import { HistogramData } from './types'; @@ -43,6 +45,14 @@ export const SignalsHistogram = React.memo( }) => { const theme = useTheme(); + const chartSize: ChartSizeArray = useMemo(() => ['100%', chartHeight], [chartHeight]); + const xAxisId = useMemo(() => getAxisId('signalsHistogramAxisX'), []); + const yAxisId = useMemo(() => getAxisId('signalsHistogramAxisY'), []); + const id = useMemo(() => getSpecId('signalsHistogram'), []); + const yAccessors = useMemo(() => ['y'], []); + const splitSeriesAccessors = useMemo(() => ['g'], []); + const tickFormat = useMemo(() => histogramDateTimeFormatter([from, to]), [from, to]); + return ( <> {loading && ( @@ -54,7 +64,7 @@ export const SignalsHistogram = React.memo( /> )} - + ( theme={theme} /> - + - + @@ -84,4 +90,5 @@ export const SignalsHistogram = React.memo( ); } ); + SignalsHistogram.displayName = 'SignalsHistogram'; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/query_bar/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/query_bar/index.tsx index 88795f9195e68..fbe854c1ee346 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/query_bar/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/query_bar/index.tsx @@ -5,10 +5,10 @@ */ import { EuiFormRow, EuiMutationObserver } from '@elastic/eui'; -import { isEqual } from 'lodash/fp'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Subscription } from 'rxjs'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal'; import { Filter, @@ -99,7 +99,7 @@ export const QueryBarDefineRule = ({ const newFilters = filterManager.getFilters(); const { filters } = field.value as FieldValueQueryBar; - if (!isEqual(filters, newFilters)) { + if (!deepEqual(filters, newFilters)) { field.setValue({ ...(field.value as FieldValueQueryBar), filters: newFilters }); } } @@ -117,10 +117,10 @@ export const QueryBarDefineRule = ({ let isSubscribed = true; async function updateFilterQueryFromValue() { const { filters, query, saved_id: savedId } = field.value as FieldValueQueryBar; - if (!isEqual(query, queryDraft)) { + if (!deepEqual(query, queryDraft)) { setQueryDraft(query); } - if (!isEqual(filters, filterManager.getFilters())) { + if (!deepEqual(filters, filterManager.getFilters())) { filterManager.setFilters(filters); } if ( @@ -148,7 +148,7 @@ export const QueryBarDefineRule = ({ const onSubmitQuery = useCallback( (newQuery: Query, timefilter?: SavedQueryTimeFilter) => { const { query } = field.value as FieldValueQueryBar; - if (!isEqual(query, newQuery)) { + if (!deepEqual(query, newQuery)) { field.setValue({ ...(field.value as FieldValueQueryBar), query: newQuery }); } }, @@ -158,7 +158,7 @@ export const QueryBarDefineRule = ({ const onChangedQuery = useCallback( (newQuery: Query) => { const { query } = field.value as FieldValueQueryBar; - if (!isEqual(query, newQuery)) { + if (!deepEqual(query, newQuery)) { field.setValue({ ...(field.value as FieldValueQueryBar), query: newQuery }); } }, diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/index.tsx index 2c9173cbeb694..ac457d7345c29 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/index.tsx @@ -12,8 +12,8 @@ import { EuiLoadingSpinner, EuiText, } from '@elastic/eui'; -import { isEqual } from 'lodash/fp'; import React, { memo, useCallback, useEffect, useState } from 'react'; +import deepEqual from 'fast-deep-equal'; import { useRuleStatus, RuleInfoStatus } from '../../../../../containers/detection_engine/rules'; import { FormattedDate } from '../../../../../components/formatted_date'; @@ -43,7 +43,7 @@ const RuleStatusComponent: React.FC = ({ ruleId, ruleEnabled }) }, [fetchRuleStatus, myRuleEnabled, ruleId, ruleEnabled, setMyRuleEnabled]); useEffect(() => { - if (!isEqual(currentStatus, ruleStatus?.current_status)) { + if (!deepEqual(currentStatus, ruleStatus?.current_status)) { setCurrentStatus(ruleStatus?.current_status ?? null); } }, [currentStatus, ruleStatus, setCurrentStatus]); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.tsx index 45da7d081333e..431d793d6e68a 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.tsx @@ -13,9 +13,9 @@ import { EuiSpacer, EuiButtonEmpty, } from '@elastic/eui'; -import { isEqual } from 'lodash/fp'; import React, { FC, memo, useCallback, useEffect, useState } from 'react'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal'; import { setFieldValue } from '../../helpers'; import { RuleStepProps, RuleStep, AboutStepRule } from '../../types'; @@ -103,7 +103,7 @@ const StepAboutRuleComponent: FC = ({ useEffect(() => { const { isNew, ...initDefaultValue } = myStepData; - if (defaultValues != null && !isEqual(initDefaultValue, defaultValues)) { + if (defaultValues != null && !deepEqual(initDefaultValue, defaultValues)) { const myDefaultValues = { ...defaultValues, isNew: false, diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_define_rule/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_define_rule/index.tsx index 920a9f2dfe56c..773eb44efb26c 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_define_rule/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_define_rule/index.tsx @@ -11,9 +11,10 @@ import { EuiFlexItem, EuiButton, } from '@elastic/eui'; -import { isEmpty, isEqual } from 'lodash/fp'; +import { isEmpty } from 'lodash/fp'; import React, { FC, memo, useCallback, useState, useEffect } from 'react'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal'; import { IIndexPattern } from '../../../../../../../../../../src/plugins/data/public'; import { useFetchIndexPatterns } from '../../../../../containers/detection_engine/rules'; @@ -126,9 +127,9 @@ const StepDefineRuleComponent: FC = ({ useEffect(() => { if (indicesConfig != null && defaultValues != null) { const myDefaultValues = getStepDefaultValue(indicesConfig, defaultValues); - if (!isEqual(myDefaultValues, myStepData)) { + if (!deepEqual(myDefaultValues, myStepData)) { setMyStepData(myDefaultValues); - setLocalUseIndicesConfig(isEqual(myDefaultValues.index, indicesConfig)); + setLocalUseIndicesConfig(deepEqual(myDefaultValues.index, indicesConfig)); setFieldValue(form, schema, myDefaultValues); } } @@ -212,13 +213,13 @@ const StepDefineRuleComponent: FC = ({ {({ index }) => { if (index != null) { - if (isEqual(index, indicesConfig) && !localUseIndicesConfig) { + if (deepEqual(index, indicesConfig) && !localUseIndicesConfig) { setLocalUseIndicesConfig(true); } - if (!isEqual(index, indicesConfig) && localUseIndicesConfig) { + if (!deepEqual(index, indicesConfig) && localUseIndicesConfig) { setLocalUseIndicesConfig(false); } - if (index != null && !isEmpty(index) && !isEqual(index, mylocalIndicesConfig)) { + if (index != null && !isEmpty(index) && !deepEqual(index, mylocalIndicesConfig)) { setMyLocalIndicesConfig(index); } } diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_schedule_rule/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_schedule_rule/index.tsx index cfbb0a622c721..2e2c7e068dd85 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_schedule_rule/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_schedule_rule/index.tsx @@ -5,8 +5,8 @@ */ import { EuiHorizontalRule, EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui'; -import { isEqual } from 'lodash/fp'; import React, { FC, memo, useCallback, useEffect, useState } from 'react'; +import deepEqual from 'fast-deep-equal'; import { setFieldValue } from '../../helpers'; import { RuleStep, RuleStepProps, ScheduleStepRule } from '../../types'; @@ -62,7 +62,7 @@ const StepScheduleRuleComponent: FC = ({ useEffect(() => { const { isNew, ...initDefaultValue } = myStepData; - if (defaultValues != null && !isEqual(initDefaultValue, defaultValues)) { + if (defaultValues != null && !deepEqual(initDefaultValue, defaultValues)) { const myDefaultValues = { ...defaultValues, isNew: false, diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx index 41eb620850a7f..f5efd9248029d 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx @@ -73,32 +73,25 @@ export const HostDetailsTabs = React.memo( return ( - } - /> - } - /> - } - /> - ( - - )} - /> - } - /> - } - /> + + + + + + + + + + + + + + + + + + + ); } diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx index 0b83710a13293..80c35e5563c1d 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { memo } from 'react'; +import React, { memo, useCallback } from 'react'; import { Route, Switch } from 'react-router-dom'; import { HostsTabsProps } from './types'; @@ -22,7 +22,7 @@ import { } from './navigation'; import { HostAlertsQueryTabBody } from './navigation/alerts_query_tab_body'; -const HostsTabs = memo( +export const HostsTabs = memo( ({ deleteQuery, filterQuery, @@ -44,49 +44,48 @@ const HostsTabs = memo( startDate: from, type, indexPattern, - narrowDateRange: (score: Anomaly, interval: string) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }, + narrowDateRange: useCallback( + (score: Anomaly, interval: string) => { + const fromTo = scoreIntervalToDateTime(score, interval); + setAbsoluteRangeDatePicker({ + id: 'global', + from: fromTo.from, + to: fromTo.to, + }); + }, + [setAbsoluteRangeDatePicker] + ), + updateDateRange: useCallback( + (min: number, max: number) => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, + [setAbsoluteRangeDatePicker] + ), }; return ( - } - /> - } - /> - } - /> - ( - - )} - /> - } - /> - } - /> + + + + + + + + + + + + + + + + + + ); } ); HostsTabs.displayName = 'HostsTabs'; - -export { HostsTabs }; diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx b/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx index 23a619db97ee4..b6b54b68ac06a 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx @@ -23,77 +23,82 @@ import { TlsQueryTabBody } from './tls_query_tab_body'; import { Anomaly } from '../../../components/ml/types'; import { NetworkAlertsQueryTabBody } from './alerts_query_tab_body'; -export const NetworkRoutes = ({ - networkPagePath, - type, - to, - filterQuery, - isInitializing, - from, - indexPattern, - setQuery, - setAbsoluteRangeDatePicker, -}: NetworkRoutesProps) => { - const narrowDateRange = useCallback( - (score: Anomaly, interval: string) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }, - [setAbsoluteRangeDatePicker] - ); +export const NetworkRoutes = React.memo( + ({ + networkPagePath, + type, + to, + filterQuery, + isInitializing, + from, + indexPattern, + setQuery, + setAbsoluteRangeDatePicker, + }) => { + const narrowDateRange = useCallback( + (score: Anomaly, interval: string) => { + const fromTo = scoreIntervalToDateTime(score, interval); + setAbsoluteRangeDatePicker({ + id: 'global', + from: fromTo.from, + to: fromTo.to, + }); + }, + [setAbsoluteRangeDatePicker] + ); + const updateDateRange = useCallback( + (min: number, max: number) => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, + [setAbsoluteRangeDatePicker] + ); - const networkAnomaliesFilterQuery = { - bool: { - should: [ - { - exists: { - field: 'source.ip', + const networkAnomaliesFilterQuery = { + bool: { + should: [ + { + exists: { + field: 'source.ip', + }, }, - }, - { - exists: { - field: 'destination.ip', + { + exists: { + field: 'destination.ip', + }, }, - }, - ], - minimum_should_match: 1, - }, - }; + ], + minimum_should_match: 1, + }, + }; - const commonProps = { - startDate: from, - endDate: to, - skip: isInitializing, - type, - narrowDateRange, - setQuery, - filterQuery, - }; + const commonProps = { + startDate: from, + endDate: to, + skip: isInitializing, + type, + narrowDateRange, + setQuery, + filterQuery, + }; - const tabProps = { - ...commonProps, - indexPattern, - }; + const tabProps = { + ...commonProps, + indexPattern, + updateDateRange, + }; - const anomaliesProps = { - ...commonProps, - anomaliesFilterQuery: networkAnomaliesFilterQuery, - AnomaliesTableComponent: AnomaliesNetworkTable, - }; + const anomaliesProps = { + ...commonProps, + anomaliesFilterQuery: networkAnomaliesFilterQuery, + AnomaliesTableComponent: AnomaliesNetworkTable, + }; - return ( - - } - /> - ( + return ( + + + + + <> @@ -118,31 +123,25 @@ export const NetworkRoutes = ({ - )} - /> - } - /> - } - /> - ( + + + + + + + + - )} - /> - } - /> - - ); -}; + + + + + + ); + } +); NetworkRoutes.displayName = 'NetworkRoutes'; diff --git a/x-pack/legacy/plugins/siem/public/routes.tsx b/x-pack/legacy/plugins/siem/public/routes.tsx index cbb58a473e8ea..a989fa9873435 100644 --- a/x-pack/legacy/plugins/siem/public/routes.tsx +++ b/x-pack/legacy/plugins/siem/public/routes.tsx @@ -20,8 +20,12 @@ const PageRouterComponent: FC = ({ history }) => ( - } /> - } /> + + + + + + diff --git a/x-pack/legacy/plugins/siem/public/utils/kql/use_update_kql.tsx b/x-pack/legacy/plugins/siem/public/utils/kql/use_update_kql.tsx index 213b881bd2084..af993588f7e0d 100644 --- a/x-pack/legacy/plugins/siem/public/utils/kql/use_update_kql.tsx +++ b/x-pack/legacy/plugins/siem/public/utils/kql/use_update_kql.tsx @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEqual } from 'lodash/fp'; import { Dispatch } from 'redux'; import { IIndexPattern } from 'src/plugins/data/public'; +import deepEqual from 'fast-deep-equal'; import { KueryFilterQuery } from '../../store'; import { applyKqlFilterQuery as dispatchApplyTimelineFilterQuery } from '../../store/timeline/actions'; @@ -29,7 +29,7 @@ export const useUpdateKql = ({ timelineId, }: UseUpdateKqlProps): RefetchKql => { const updateKql: RefetchKql = (dispatch: Dispatch) => { - if (kueryFilterQueryDraft != null && !isEqual(kueryFilterQuery, kueryFilterQueryDraft)) { + if (kueryFilterQueryDraft != null && !deepEqual(kueryFilterQuery, kueryFilterQueryDraft)) { if (storeType === 'timelineType' && timelineId != null) { dispatch( dispatchApplyTimelineFilterQuery({ diff --git a/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx b/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx index c88562abef6ae..ddee2359b28ba 100644 --- a/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx +++ b/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx @@ -5,7 +5,6 @@ */ import * as H from 'history'; -import { isEqual } from 'lodash/fp'; import { memo, useEffect, useState } from 'react'; import { withRouter } from 'react-router-dom'; import deepEqual from 'fast-deep-equal'; @@ -35,7 +34,7 @@ export const SpyRouteComponent = memo( } }, [search]); useEffect(() => { - if (pageName && !isEqual(route.pathName, pathname)) { + if (pageName && !deepEqual(route.pathName, pathname)) { if (isInitializing && detailName == null) { dispatch({ type: 'updateRouteWithOutSearch', diff --git a/x-pack/package.json b/x-pack/package.json index f76b0182ea228..b8fe0326903b6 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -106,6 +106,7 @@ "@types/uuid": "^3.4.4", "@types/xml-crypto": "^1.4.0", "@types/xml2js": "^0.4.5", + "@welldone-software/why-did-you-render": "^4.0.0", "abab": "^1.0.4", "axios": "^0.19.0", "babel-jest": "^24.9.0", diff --git a/x-pack/tsconfig.json b/x-pack/tsconfig.json index 978271166cc05..723da7cef6a77 100644 --- a/x-pack/tsconfig.json +++ b/x-pack/tsconfig.json @@ -36,7 +36,7 @@ "x-pack/test_utils/*" ], "plugins/*": ["src/legacy/core_plugins/*/public/"], - "fixtures/*": ["src/fixtures/*"] + "fixtures/*": ["src/fixtures/*"], }, "types": [ "node", diff --git a/yarn.lock b/yarn.lock index f46e869909e2e..7906f363813b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5684,6 +5684,13 @@ text-table "^0.2.0" webpack-log "^1.1.2" +"@welldone-software/why-did-you-render@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@welldone-software/why-did-you-render/-/why-did-you-render-4.0.0.tgz#cc98c996f5a06ea55bd07dc99ba4b4d68af93332" + integrity sha512-PjqriZ8Ak9biP2+kOcIrg+NwsFwWVhGV03Hm+ns84YBCArn+hWBKM9rMBEU6e62I1qyrYF2/G9yktNpEmfWfJA== + dependencies: + lodash "^4" + "@wry/context@^0.4.0": version "0.4.1" resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.4.1.tgz#b3e23ca036035cbad0bd9711269352dd03a6fe3c" @@ -19767,7 +19774,7 @@ lodash.uniqby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= -lodash@4.17.11, lodash@4.17.15, lodash@>4.17.4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.10.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.1, lodash@~4.17.10, lodash@~4.17.15, lodash@~4.17.5: +lodash@4.17.11, lodash@4.17.15, lodash@>4.17.4, lodash@^4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.10.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.1, lodash@~4.17.10, lodash@~4.17.15, lodash@~4.17.5: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== From d339740c2de9f61d7140cd9bc983383f2843df67 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Tue, 25 Feb 2020 09:27:18 -0500 Subject: [PATCH 054/123] [Uptime] Migrate server to new platform (#53939) * Move uptime legacy server to plugins directory. * Re-add feature registration code. * Move feature registration back to kibana bootstrap file. * Delete obsolete test file. * Remove i18n call from untracked file. * Implement feedback. Co-authored-by: Elastic Machine --- .../plugins/uptime/common/constants/plugin.ts | 7 ++- x-pack/legacy/plugins/uptime/index.ts | 19 -------- .../plugins/uptime/scripts/graphql_schemas.ts | 15 ------ .../__tests__/find_potential_matches_test.ts | 5 -- x-pack/legacy/plugins/uptime/server/plugin.ts | 19 -------- x-pack/plugins/uptime/kibana.json | 9 ++++ .../uptime/server/graphql/constants.ts | 0 .../plugins/uptime/server/graphql/index.ts | 0 .../server/graphql/monitor_states/index.ts | 0 .../graphql/monitor_states/resolvers.ts | 6 +-- .../graphql/monitor_states/schema.gql.ts | 0 .../uptime/server/graphql/monitors/index.ts | 0 .../server/graphql/monitors/resolvers.ts | 10 +++- .../server/graphql/monitors/schema.gql.ts | 0 .../uptime/server/graphql/pings/index.ts | 0 .../uptime/server/graphql/pings/resolvers.ts | 7 ++- .../uptime/server/graphql/pings/schema.gql.ts | 0 .../plugins/uptime/server/graphql/types.ts | 0 .../__tests__/parse_literal.test.ts | 0 .../__tests__/parse_value.test.ts | 0 .../__tests__/serialize.test.ts | 0 .../graphql/unsigned_int_scalar/index.ts | 0 .../graphql/unsigned_int_scalar/resolvers.ts | 0 .../graphql/unsigned_int_scalar/schema.gql.ts | 0 .../plugins/uptime/server/index.ts | 6 ++- .../plugins/uptime/server/kibana.index.ts | 17 +++---- .../lib/adapters/framework/adapter_types.ts | 11 ++--- .../server/lib/adapters/framework/index.ts | 0 .../framework/kibana_framework_adapter.ts | 0 .../uptime/server/lib/adapters/index.ts | 0 .../kibana_telemetry_adapter.test.ts.snap | 0 .../kibana_telemetry_adapter.test.ts | 0 .../server/lib/adapters/telemetry/index.ts | 0 .../telemetry/kibana_telemetry_adapter.ts | 0 .../uptime/server/lib/compose/kibana.ts | 4 +- .../__snapshots__/license.test.ts.snap | 0 .../lib/domains/__tests__/license.test.ts | 2 +- .../uptime/server/lib/domains/index.ts | 0 .../uptime/server/lib/domains/license.ts | 2 +- .../assert_close_to.test.ts.snap | 0 .../get_filter_clause.test.ts.snap | 0 .../helper/__test__/assert_close_to.test.ts | 0 .../helper/__test__/get_filter_clause.test.ts | 0 .../__test__/get_histogram_interval.test.ts | 0 .../get_histogram_interval_formatted.test.ts | 0 .../__test__/parse_relative_date.test.ts | 0 .../server/lib/helper/assert_close_to.ts | 0 .../server/lib/helper/get_filter_clause.ts | 0 .../lib/helper/get_histogram_interval.ts | 2 +- .../get_histogram_interval_formatted.ts | 0 .../plugins/uptime/server/lib/helper/index.ts | 0 .../lib/helper/make_date_rate_filter.ts | 0 .../server/lib/helper/object_to_array.ts | 0 .../plugins/uptime/server/lib/lib.ts | 0 .../extract_filter_aggs_results.test.ts.snap | 0 .../generate_filter_aggs.test.ts.snap | 0 .../get_monitor_charts.test.ts.snap | 0 .../get_ping_histogram.test.ts.snap | 0 .../combine_range_with_filters.test.ts | 0 .../extract_filter_aggs_results.test.ts | 0 .../__tests__/generate_filter_aggs.test.ts | 0 .../__tests__/get_latest_monitor.test.ts | 0 .../__tests__/get_monitor_charts.test.ts | 0 .../__tests__/get_ping_histogram.test.ts | 0 .../lib/requests/__tests__/get_pings.test.ts | 0 .../__tests__/monitor_charts_mock.json | 0 .../lib/requests/generate_filter_aggs.ts | 0 .../server/lib/requests/get_filter_bar.ts | 4 +- .../server/lib/requests/get_index_pattern.ts | 4 +- .../server/lib/requests/get_index_status.ts | 4 +- .../server/lib/requests/get_latest_monitor.ts | 4 +- .../uptime/server/lib/requests/get_monitor.ts | 4 +- .../server/lib/requests/get_monitor_charts.ts | 7 ++- .../lib/requests/get_monitor_details.ts | 7 ++- .../lib/requests/get_monitor_locations.ts | 10 +++- .../server/lib/requests/get_monitor_states.ts | 8 +++- .../server/lib/requests/get_ping_histogram.ts | 4 +- .../uptime/server/lib/requests/get_pings.ts | 8 +++- .../lib/requests/get_snapshot_counts.ts | 7 ++- .../uptime/server/lib/requests/index.ts | 0 .../search/__tests__/fetch_page.test.ts | 2 +- .../__tests__/monitor_group_iterator.test.ts | 0 .../search/__tests__/query_context.test.ts | 5 +- .../requests/search/__tests__/test_helpers.ts | 5 +- .../requests/search/enrich_monitor_groups.ts | 4 +- .../server/lib/requests/search/fetch_chunk.ts | 0 .../server/lib/requests/search/fetch_page.ts | 8 +++- .../requests/search/find_potential_matches.ts | 4 +- .../server/lib/requests/search/index.ts | 0 .../requests/search/monitor_group_iterator.ts | 2 +- .../lib/requests/search/query_context.ts | 2 +- .../search/refine_potential_matches.ts | 4 +- .../server/lib/requests/search/types.ts | 5 +- .../uptime/server/lib/requests/types.ts | 7 ++- .../server/lib/requests/uptime_requests.ts | 11 +++-- x-pack/plugins/uptime/server/plugin.ts | 17 +++++++ .../server/rest_api/create_route_with_auth.ts | 0 .../plugins/uptime/server/rest_api/index.ts | 0 .../index_pattern/get_index_pattern.ts | 0 .../server/rest_api/index_pattern/index.ts | 0 .../uptime/server/rest_api/monitors/index.ts | 0 .../rest_api/monitors/monitor_locations.ts | 0 .../rest_api/monitors/monitors_details.ts | 0 .../uptime/server/rest_api/monitors/status.ts | 0 .../overview_filters/get_overview_filters.ts | 0 .../server/rest_api/overview_filters/index.ts | 0 .../uptime/server/rest_api/pings/get_all.ts | 48 +++++++++++++++++++ .../rest_api/pings/get_ping_histogram.ts | 0 .../uptime/server/rest_api/pings/get_pings.ts | 0 .../uptime/server/rest_api/pings/index.ts | 0 .../rest_api/snapshot/get_snapshot_count.ts | 0 .../uptime/server/rest_api/snapshot/index.ts | 0 .../uptime/server/rest_api/telemetry/index.ts | 0 .../rest_api/telemetry/log_monitor_page.ts | 0 .../rest_api/telemetry/log_overview_page.ts | 0 .../plugins/uptime/server/rest_api/types.ts | 0 .../server/rest_api/uptime_route_wrapper.ts | 0 .../plugins/uptime/server/uptime_server.ts | 0 .../apis/uptime/rest/ping_histogram.ts | 2 +- 119 files changed, 204 insertions(+), 134 deletions(-) delete mode 100644 x-pack/legacy/plugins/uptime/scripts/graphql_schemas.ts delete mode 100644 x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/find_potential_matches_test.ts delete mode 100644 x-pack/legacy/plugins/uptime/server/plugin.ts create mode 100644 x-pack/plugins/uptime/kibana.json rename x-pack/{legacy => }/plugins/uptime/server/graphql/constants.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/monitor_states/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/monitor_states/resolvers.ts (89%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/monitor_states/schema.gql.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/monitors/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/monitors/resolvers.ts (71%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/monitors/schema.gql.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/pings/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/pings/resolvers.ts (84%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/pings/schema.gql.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/types.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/parse_literal.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/parse_value.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/serialize.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/unsigned_int_scalar/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/unsigned_int_scalar/resolvers.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/graphql/unsigned_int_scalar/schema.gql.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/index.ts (59%) rename x-pack/{legacy => }/plugins/uptime/server/kibana.index.ts (82%) rename x-pack/{legacy => }/plugins/uptime/server/lib/adapters/framework/adapter_types.ts (85%) rename x-pack/{legacy => }/plugins/uptime/server/lib/adapters/framework/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/adapters/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/adapters/telemetry/__tests__/__snapshots__/kibana_telemetry_adapter.test.ts.snap (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/adapters/telemetry/__tests__/kibana_telemetry_adapter.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/adapters/telemetry/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/adapters/telemetry/kibana_telemetry_adapter.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/compose/kibana.ts (80%) rename x-pack/{legacy => }/plugins/uptime/server/lib/domains/__tests__/__snapshots__/license.test.ts.snap (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/domains/__tests__/license.test.ts (93%) rename x-pack/{legacy => }/plugins/uptime/server/lib/domains/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/domains/license.ts (93%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/__test__/__snapshots__/assert_close_to.test.ts.snap (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/__test__/__snapshots__/get_filter_clause.test.ts.snap (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/__test__/assert_close_to.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/__test__/get_filter_clause.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/__test__/get_histogram_interval.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/__test__/get_histogram_interval_formatted.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/__test__/parse_relative_date.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/assert_close_to.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/get_filter_clause.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/get_histogram_interval.ts (95%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/get_histogram_interval_formatted.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/make_date_rate_filter.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/helper/object_to_array.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/lib.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/__tests__/__snapshots__/extract_filter_aggs_results.test.ts.snap (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/__tests__/__snapshots__/generate_filter_aggs.test.ts.snap (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/__tests__/__snapshots__/get_monitor_charts.test.ts.snap (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/__tests__/__snapshots__/get_ping_histogram.test.ts.snap (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/__tests__/combine_range_with_filters.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/__tests__/extract_filter_aggs_results.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/__tests__/generate_filter_aggs.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/__tests__/monitor_charts_mock.json (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/generate_filter_aggs.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/get_filter_bar.ts (94%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/get_index_pattern.ts (92%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/get_index_status.ts (76%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/get_latest_monitor.ts (91%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/get_monitor.ts (87%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/get_monitor_charts.ts (96%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/get_monitor_details.ts (88%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/get_monitor_locations.ts (92%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/get_monitor_states.ts (89%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/get_ping_histogram.ts (93%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/get_pings.ts (93%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/get_snapshot_counts.ts (96%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/__tests__/fetch_page.test.ts (96%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/__tests__/monitor_group_iterator.test.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/__tests__/query_context.test.ts (95%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/__tests__/test_helpers.ts (88%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/enrich_monitor_groups.ts (98%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/fetch_chunk.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/fetch_page.ts (96%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/find_potential_matches.ts (95%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/monitor_group_iterator.ts (98%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/query_context.ts (97%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts (96%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/search/types.ts (76%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/types.ts (89%) rename x-pack/{legacy => }/plugins/uptime/server/lib/requests/uptime_requests.ts (83%) create mode 100644 x-pack/plugins/uptime/server/plugin.ts rename x-pack/{legacy => }/plugins/uptime/server/rest_api/create_route_with_auth.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/index_pattern/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/monitors/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/monitors/monitor_locations.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/monitors/monitors_details.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/monitors/status.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/overview_filters/get_overview_filters.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/overview_filters/index.ts (100%) create mode 100644 x-pack/plugins/uptime/server/rest_api/pings/get_all.ts rename x-pack/{legacy => }/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/pings/get_pings.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/pings/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/snapshot/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/telemetry/index.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/telemetry/log_monitor_page.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/telemetry/log_overview_page.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/types.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/rest_api/uptime_route_wrapper.ts (100%) rename x-pack/{legacy => }/plugins/uptime/server/uptime_server.ts (100%) diff --git a/x-pack/legacy/plugins/uptime/common/constants/plugin.ts b/x-pack/legacy/plugins/uptime/common/constants/plugin.ts index f6fa569a50315..00781726941d5 100644 --- a/x-pack/legacy/plugins/uptime/common/constants/plugin.ts +++ b/x-pack/legacy/plugins/uptime/common/constants/plugin.ts @@ -4,11 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; + export const PLUGIN = { APP_ROOT_ID: 'react-uptime-root', DESCRIPTION: 'Uptime monitoring', ID: 'uptime', - ROUTER_BASE_NAME: '/app/uptime#', LOCAL_STORAGE_KEY: 'xpack.uptime', + NAME: i18n.translate('xpack.uptime.featureRegistry.uptimeFeatureName', { + defaultMessage: 'Uptime', + }), + ROUTER_BASE_NAME: '/app/uptime#', TITLE: 'uptime', }; diff --git a/x-pack/legacy/plugins/uptime/index.ts b/x-pack/legacy/plugins/uptime/index.ts index cf7332f97d466..feecef5857895 100644 --- a/x-pack/legacy/plugins/uptime/index.ts +++ b/x-pack/legacy/plugins/uptime/index.ts @@ -6,9 +6,7 @@ import { i18n } from '@kbn/i18n'; import { resolve } from 'path'; -import { PluginInitializerContext } from 'src/core/server'; import { PLUGIN } from './common/constants'; -import { KibanaServer, plugin } from './server'; import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/utils'; export const uptime = (kibana: any) => @@ -35,21 +33,4 @@ export const uptime = (kibana: any) => }, home: ['plugins/uptime/register_feature'], }, - init(server: KibanaServer) { - const initializerContext = {} as PluginInitializerContext; - const { savedObjects } = server; - const { xpack_main } = server.plugins; - const { usageCollection } = server.newPlatform.setup.plugins; - - plugin(initializerContext).setup( - { - route: server.newPlatform.setup.core.http.createRouter(), - }, - { - savedObjects, - usageCollection, - xpack: xpack_main, - } - ); - }, }); diff --git a/x-pack/legacy/plugins/uptime/scripts/graphql_schemas.ts b/x-pack/legacy/plugins/uptime/scripts/graphql_schemas.ts deleted file mode 100644 index c337cf098e48d..0000000000000 --- a/x-pack/legacy/plugins/uptime/scripts/graphql_schemas.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { buildSchemaFromTypeDefinitions } from 'graphql-tools'; -import { typeDefs } from '../server/graphql'; - -export const schemas = [...typeDefs]; - -// this default export is used to feed the combined types to the gql-gen tool -// which generates the corresponding typescript types -// eslint-disable-next-line import/no-default-export -export default buildSchemaFromTypeDefinitions(schemas); diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/find_potential_matches_test.ts b/x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/find_potential_matches_test.ts deleted file mode 100644 index 41bc2aa258807..0000000000000 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/find_potential_matches_test.ts +++ /dev/null @@ -1,5 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ diff --git a/x-pack/legacy/plugins/uptime/server/plugin.ts b/x-pack/legacy/plugins/uptime/server/plugin.ts deleted file mode 100644 index acecce305e7cb..0000000000000 --- a/x-pack/legacy/plugins/uptime/server/plugin.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { PluginInitializerContext } from 'src/core/server'; -import { initServerWithKibana } from './kibana.index'; -import { UptimeCoreSetup, UptimeCorePlugins } from './lib/adapters/framework'; - -export function plugin(initializerContext: PluginInitializerContext) { - return new Plugin(); -} - -export class Plugin { - public setup(core: UptimeCoreSetup, plugins: UptimeCorePlugins) { - initServerWithKibana(core, plugins); - } -} diff --git a/x-pack/plugins/uptime/kibana.json b/x-pack/plugins/uptime/kibana.json new file mode 100644 index 0000000000000..dd61716325afc --- /dev/null +++ b/x-pack/plugins/uptime/kibana.json @@ -0,0 +1,9 @@ +{ + "configPath": ["xpack"], + "id": "uptime", + "kibanaVersion": "kibana", + "requiredPlugins": ["features", "licensing", "usageCollection"], + "server": true, + "ui": false, + "version": "8.0.0" +} diff --git a/x-pack/legacy/plugins/uptime/server/graphql/constants.ts b/x-pack/plugins/uptime/server/graphql/constants.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/constants.ts rename to x-pack/plugins/uptime/server/graphql/constants.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/index.ts b/x-pack/plugins/uptime/server/graphql/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/index.ts rename to x-pack/plugins/uptime/server/graphql/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/monitor_states/index.ts b/x-pack/plugins/uptime/server/graphql/monitor_states/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/monitor_states/index.ts rename to x-pack/plugins/uptime/server/graphql/monitor_states/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/monitor_states/resolvers.ts b/x-pack/plugins/uptime/server/graphql/monitor_states/resolvers.ts similarity index 89% rename from x-pack/legacy/plugins/uptime/server/graphql/monitor_states/resolvers.ts rename to x-pack/plugins/uptime/server/graphql/monitor_states/resolvers.ts index e2b076d570843..6ac42f7717259 100644 --- a/x-pack/legacy/plugins/uptime/server/graphql/monitor_states/resolvers.ts +++ b/x-pack/plugins/uptime/server/graphql/monitor_states/resolvers.ts @@ -6,13 +6,13 @@ import { CreateUMGraphQLResolvers, UMContext } from '../types'; import { UMServerLibs } from '../../lib/lib'; -import { UMResolver } from '../../../common/graphql/resolver_types'; +import { UMResolver } from '../../../../../legacy/plugins/uptime/common/graphql/resolver_types'; import { GetMonitorStatesQueryArgs, MonitorSummaryResult, StatesIndexStatus, -} from '../../../common/graphql/types'; -import { CONTEXT_DEFAULTS } from '../../../common/constants/context_defaults'; +} from '../../../../../legacy/plugins/uptime/common/graphql/types'; +import { CONTEXT_DEFAULTS } from '../../../../../legacy/plugins/uptime/common/constants/context_defaults'; export type UMGetMonitorStatesResolver = UMResolver< MonitorSummaryResult | Promise, diff --git a/x-pack/legacy/plugins/uptime/server/graphql/monitor_states/schema.gql.ts b/x-pack/plugins/uptime/server/graphql/monitor_states/schema.gql.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/monitor_states/schema.gql.ts rename to x-pack/plugins/uptime/server/graphql/monitor_states/schema.gql.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/monitors/index.ts b/x-pack/plugins/uptime/server/graphql/monitors/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/monitors/index.ts rename to x-pack/plugins/uptime/server/graphql/monitors/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/monitors/resolvers.ts b/x-pack/plugins/uptime/server/graphql/monitors/resolvers.ts similarity index 71% rename from x-pack/legacy/plugins/uptime/server/graphql/monitors/resolvers.ts rename to x-pack/plugins/uptime/server/graphql/monitors/resolvers.ts index 19f23fa1bb934..b39c5f42bfd75 100644 --- a/x-pack/legacy/plugins/uptime/server/graphql/monitors/resolvers.ts +++ b/x-pack/plugins/uptime/server/graphql/monitors/resolvers.ts @@ -4,11 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import { UMResolver } from '../../../common/graphql/resolver_types'; -import { GetMonitorChartsDataQueryArgs, MonitorChart } from '../../../common/graphql/types'; +import { UMGqlRange } from '../../../../../legacy/plugins/uptime/common/domain_types'; +import { UMResolver } from '../../../../../legacy/plugins/uptime/common/graphql/resolver_types'; +import { + GetMonitorChartsDataQueryArgs, + MonitorChart, +} from '../../../../../legacy/plugins/uptime/common/graphql/types'; import { UMServerLibs } from '../../lib/lib'; import { CreateUMGraphQLResolvers, UMContext } from '../types'; +export type UMMonitorsResolver = UMResolver, any, UMGqlRange, UMContext>; + export type UMGetMonitorChartsResolver = UMResolver< any | Promise, any, diff --git a/x-pack/legacy/plugins/uptime/server/graphql/monitors/schema.gql.ts b/x-pack/plugins/uptime/server/graphql/monitors/schema.gql.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/monitors/schema.gql.ts rename to x-pack/plugins/uptime/server/graphql/monitors/schema.gql.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/pings/index.ts b/x-pack/plugins/uptime/server/graphql/pings/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/pings/index.ts rename to x-pack/plugins/uptime/server/graphql/pings/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/pings/resolvers.ts b/x-pack/plugins/uptime/server/graphql/pings/resolvers.ts similarity index 84% rename from x-pack/legacy/plugins/uptime/server/graphql/pings/resolvers.ts rename to x-pack/plugins/uptime/server/graphql/pings/resolvers.ts index de83a9ced16b2..b383fc5d5fb15 100644 --- a/x-pack/legacy/plugins/uptime/server/graphql/pings/resolvers.ts +++ b/x-pack/plugins/uptime/server/graphql/pings/resolvers.ts @@ -4,8 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { UMResolver } from '../../../common/graphql/resolver_types'; -import { AllPingsQueryArgs, PingResults } from '../../../common/graphql/types'; +import { UMResolver } from '../../../../../legacy/plugins/uptime/common/graphql/resolver_types'; +import { + AllPingsQueryArgs, + PingResults, +} from '../../../../../legacy/plugins/uptime/common/graphql/types'; import { UMServerLibs } from '../../lib/lib'; import { UMContext } from '../types'; import { CreateUMGraphQLResolvers } from '../types'; diff --git a/x-pack/legacy/plugins/uptime/server/graphql/pings/schema.gql.ts b/x-pack/plugins/uptime/server/graphql/pings/schema.gql.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/pings/schema.gql.ts rename to x-pack/plugins/uptime/server/graphql/pings/schema.gql.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/types.ts b/x-pack/plugins/uptime/server/graphql/types.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/types.ts rename to x-pack/plugins/uptime/server/graphql/types.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/parse_literal.test.ts b/x-pack/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/parse_literal.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/parse_literal.test.ts rename to x-pack/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/parse_literal.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/parse_value.test.ts b/x-pack/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/parse_value.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/parse_value.test.ts rename to x-pack/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/parse_value.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/serialize.test.ts b/x-pack/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/serialize.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/serialize.test.ts rename to x-pack/plugins/uptime/server/graphql/unsigned_int_scalar/__tests__/serialize.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/unsigned_int_scalar/index.ts b/x-pack/plugins/uptime/server/graphql/unsigned_int_scalar/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/unsigned_int_scalar/index.ts rename to x-pack/plugins/uptime/server/graphql/unsigned_int_scalar/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/unsigned_int_scalar/resolvers.ts b/x-pack/plugins/uptime/server/graphql/unsigned_int_scalar/resolvers.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/unsigned_int_scalar/resolvers.ts rename to x-pack/plugins/uptime/server/graphql/unsigned_int_scalar/resolvers.ts diff --git a/x-pack/legacy/plugins/uptime/server/graphql/unsigned_int_scalar/schema.gql.ts b/x-pack/plugins/uptime/server/graphql/unsigned_int_scalar/schema.gql.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/graphql/unsigned_int_scalar/schema.gql.ts rename to x-pack/plugins/uptime/server/graphql/unsigned_int_scalar/schema.gql.ts diff --git a/x-pack/legacy/plugins/uptime/server/index.ts b/x-pack/plugins/uptime/server/index.ts similarity index 59% rename from x-pack/legacy/plugins/uptime/server/index.ts rename to x-pack/plugins/uptime/server/index.ts index d063f0d8c2288..bec47fa9db4cf 100644 --- a/x-pack/legacy/plugins/uptime/server/index.ts +++ b/x-pack/plugins/uptime/server/index.ts @@ -4,5 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ +import { PluginInitializerContext } from '../../../../src/core/server'; +import { Plugin } from './plugin'; + export { initServerWithKibana, KibanaServer } from './kibana.index'; -export { plugin } from './plugin'; +export const plugin = (initializerContext: PluginInitializerContext) => + new Plugin(initializerContext); diff --git a/x-pack/legacy/plugins/uptime/server/kibana.index.ts b/x-pack/plugins/uptime/server/kibana.index.ts similarity index 82% rename from x-pack/legacy/plugins/uptime/server/kibana.index.ts rename to x-pack/plugins/uptime/server/kibana.index.ts index 73fabc629946b..c7ac3a70c0494 100644 --- a/x-pack/legacy/plugins/uptime/server/kibana.index.ts +++ b/x-pack/plugins/uptime/server/kibana.index.ts @@ -4,9 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { i18n } from '@kbn/i18n'; import { Request, Server } from 'hapi'; -import { PLUGIN } from '../common/constants'; +import { PLUGIN } from '../../../legacy/plugins/uptime/common/constants'; import { KibanaTelemetryAdapter } from './lib/adapters/telemetry'; import { compose } from './lib/compose/kibana'; import { initUptimeServer } from './uptime_server'; @@ -25,17 +24,13 @@ export interface KibanaServer extends Server { } export const initServerWithKibana = (server: UptimeCoreSetup, plugins: UptimeCorePlugins) => { - const { usageCollection, xpack } = plugins; - const libs = compose(server, plugins); + const { features, usageCollection } = plugins; + const libs = compose(server); KibanaTelemetryAdapter.registerUsageCollector(usageCollection); - initUptimeServer(libs); - - xpack.registerFeature({ + features.registerFeature({ id: PLUGIN.ID, - name: i18n.translate('xpack.uptime.featureRegistry.uptimeFeatureName', { - defaultMessage: 'Uptime', - }), + name: PLUGIN.NAME, navLinkId: PLUGIN.ID, icon: 'uptimeApp', app: ['uptime', 'kibana'], @@ -59,4 +54,6 @@ export const initServerWithKibana = (server: UptimeCoreSetup, plugins: UptimeCor }, }, }); + + initUptimeServer(libs); }; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/uptime/server/lib/adapters/framework/adapter_types.ts similarity index 85% rename from x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts rename to x-pack/plugins/uptime/server/lib/adapters/framework/adapter_types.ts index fb2052bb4c87f..8dde6050d5d36 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/uptime/server/lib/adapters/framework/adapter_types.ts @@ -6,13 +6,9 @@ import { GraphQLSchema } from 'graphql'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { - SavedObjectsLegacyService, - IRouter, - CallAPIOptions, - SavedObjectsClientContract, -} from 'src/core/server'; +import { IRouter, CallAPIOptions, SavedObjectsClientContract } from 'src/core/server'; import { UMKibanaRoute } from '../../../rest_api'; +import { PluginSetupContract } from '../../../../../features/server'; type APICaller = ( endpoint: string, @@ -34,9 +30,8 @@ export interface UptimeCoreSetup { } export interface UptimeCorePlugins { - savedObjects: SavedObjectsLegacyService; + features: PluginSetupContract; usageCollection: UsageCollectionSetup; - xpack: any; } export interface UMBackendFrameworkAdapter { diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/index.ts b/x-pack/plugins/uptime/server/lib/adapters/framework/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/adapters/framework/index.ts rename to x-pack/plugins/uptime/server/lib/adapters/framework/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts rename to x-pack/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/index.ts b/x-pack/plugins/uptime/server/lib/adapters/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/adapters/index.ts rename to x-pack/plugins/uptime/server/lib/adapters/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/telemetry/__tests__/__snapshots__/kibana_telemetry_adapter.test.ts.snap b/x-pack/plugins/uptime/server/lib/adapters/telemetry/__tests__/__snapshots__/kibana_telemetry_adapter.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/adapters/telemetry/__tests__/__snapshots__/kibana_telemetry_adapter.test.ts.snap rename to x-pack/plugins/uptime/server/lib/adapters/telemetry/__tests__/__snapshots__/kibana_telemetry_adapter.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/telemetry/__tests__/kibana_telemetry_adapter.test.ts b/x-pack/plugins/uptime/server/lib/adapters/telemetry/__tests__/kibana_telemetry_adapter.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/adapters/telemetry/__tests__/kibana_telemetry_adapter.test.ts rename to x-pack/plugins/uptime/server/lib/adapters/telemetry/__tests__/kibana_telemetry_adapter.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/telemetry/index.ts b/x-pack/plugins/uptime/server/lib/adapters/telemetry/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/adapters/telemetry/index.ts rename to x-pack/plugins/uptime/server/lib/adapters/telemetry/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/telemetry/kibana_telemetry_adapter.ts b/x-pack/plugins/uptime/server/lib/adapters/telemetry/kibana_telemetry_adapter.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/adapters/telemetry/kibana_telemetry_adapter.ts rename to x-pack/plugins/uptime/server/lib/adapters/telemetry/kibana_telemetry_adapter.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/compose/kibana.ts b/x-pack/plugins/uptime/server/lib/compose/kibana.ts similarity index 80% rename from x-pack/legacy/plugins/uptime/server/lib/compose/kibana.ts rename to x-pack/plugins/uptime/server/lib/compose/kibana.ts index 875a5d9dc8c5c..edda5cb283323 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/compose/kibana.ts +++ b/x-pack/plugins/uptime/server/lib/compose/kibana.ts @@ -8,9 +8,9 @@ import { UMKibanaBackendFrameworkAdapter } from '../adapters/framework'; import * as requests from '../requests'; import { licenseCheck } from '../domains'; import { UMDomainLibs, UMServerLibs } from '../lib'; -import { UptimeCorePlugins, UptimeCoreSetup } from '../adapters/framework'; +import { UptimeCoreSetup } from '../adapters/framework'; -export function compose(server: UptimeCoreSetup, plugins: UptimeCorePlugins): UMServerLibs { +export function compose(server: UptimeCoreSetup): UMServerLibs { const framework = new UMKibanaBackendFrameworkAdapter(server); const domainLibs: UMDomainLibs = { diff --git a/x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/__snapshots__/license.test.ts.snap b/x-pack/plugins/uptime/server/lib/domains/__tests__/__snapshots__/license.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/__snapshots__/license.test.ts.snap rename to x-pack/plugins/uptime/server/lib/domains/__tests__/__snapshots__/license.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/license.test.ts b/x-pack/plugins/uptime/server/lib/domains/__tests__/license.test.ts similarity index 93% rename from x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/license.test.ts rename to x-pack/plugins/uptime/server/lib/domains/__tests__/license.test.ts index 8c47b318da9bd..b842f55fc7579 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/license.test.ts +++ b/x-pack/plugins/uptime/server/lib/domains/__tests__/license.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ILicense } from '../../../../../../../plugins/licensing/server'; +import { ILicense } from '../../../../../licensing/server'; import { licenseCheck } from '../license'; describe('license check', () => { diff --git a/x-pack/legacy/plugins/uptime/server/lib/domains/index.ts b/x-pack/plugins/uptime/server/lib/domains/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/domains/index.ts rename to x-pack/plugins/uptime/server/lib/domains/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/domains/license.ts b/x-pack/plugins/uptime/server/lib/domains/license.ts similarity index 93% rename from x-pack/legacy/plugins/uptime/server/lib/domains/license.ts rename to x-pack/plugins/uptime/server/lib/domains/license.ts index b8b5722d79877..d272424379e48 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/domains/license.ts +++ b/x-pack/plugins/uptime/server/lib/domains/license.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ILicense } from '../../../../../../plugins/licensing/server'; +import { ILicense } from '../../../../licensing/server'; export interface UMLicenseStatusResponse { statusCode: number; diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/__test__/__snapshots__/assert_close_to.test.ts.snap b/x-pack/plugins/uptime/server/lib/helper/__test__/__snapshots__/assert_close_to.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/__test__/__snapshots__/assert_close_to.test.ts.snap rename to x-pack/plugins/uptime/server/lib/helper/__test__/__snapshots__/assert_close_to.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/__test__/__snapshots__/get_filter_clause.test.ts.snap b/x-pack/plugins/uptime/server/lib/helper/__test__/__snapshots__/get_filter_clause.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/__test__/__snapshots__/get_filter_clause.test.ts.snap rename to x-pack/plugins/uptime/server/lib/helper/__test__/__snapshots__/get_filter_clause.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/__test__/assert_close_to.test.ts b/x-pack/plugins/uptime/server/lib/helper/__test__/assert_close_to.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/__test__/assert_close_to.test.ts rename to x-pack/plugins/uptime/server/lib/helper/__test__/assert_close_to.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/__test__/get_filter_clause.test.ts b/x-pack/plugins/uptime/server/lib/helper/__test__/get_filter_clause.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/__test__/get_filter_clause.test.ts rename to x-pack/plugins/uptime/server/lib/helper/__test__/get_filter_clause.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/__test__/get_histogram_interval.test.ts b/x-pack/plugins/uptime/server/lib/helper/__test__/get_histogram_interval.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/__test__/get_histogram_interval.test.ts rename to x-pack/plugins/uptime/server/lib/helper/__test__/get_histogram_interval.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/__test__/get_histogram_interval_formatted.test.ts b/x-pack/plugins/uptime/server/lib/helper/__test__/get_histogram_interval_formatted.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/__test__/get_histogram_interval_formatted.test.ts rename to x-pack/plugins/uptime/server/lib/helper/__test__/get_histogram_interval_formatted.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/__test__/parse_relative_date.test.ts b/x-pack/plugins/uptime/server/lib/helper/__test__/parse_relative_date.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/__test__/parse_relative_date.test.ts rename to x-pack/plugins/uptime/server/lib/helper/__test__/parse_relative_date.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/assert_close_to.ts b/x-pack/plugins/uptime/server/lib/helper/assert_close_to.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/assert_close_to.ts rename to x-pack/plugins/uptime/server/lib/helper/assert_close_to.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/get_filter_clause.ts b/x-pack/plugins/uptime/server/lib/helper/get_filter_clause.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/get_filter_clause.ts rename to x-pack/plugins/uptime/server/lib/helper/get_filter_clause.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/get_histogram_interval.ts b/x-pack/plugins/uptime/server/lib/helper/get_histogram_interval.ts similarity index 95% rename from x-pack/legacy/plugins/uptime/server/lib/helper/get_histogram_interval.ts rename to x-pack/plugins/uptime/server/lib/helper/get_histogram_interval.ts index 26515fb4b4c63..fb44f5727aab3 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/helper/get_histogram_interval.ts +++ b/x-pack/plugins/uptime/server/lib/helper/get_histogram_interval.ts @@ -5,7 +5,7 @@ */ import DateMath from '@elastic/datemath'; -import { QUERY } from '../../../common/constants'; +import { QUERY } from '../../../../../legacy/plugins/uptime/common/constants'; export const parseRelativeDate = (dateStr: string, options = {}) => { // We need this this parsing because if user selects This week or this date diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/get_histogram_interval_formatted.ts b/x-pack/plugins/uptime/server/lib/helper/get_histogram_interval_formatted.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/get_histogram_interval_formatted.ts rename to x-pack/plugins/uptime/server/lib/helper/get_histogram_interval_formatted.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/index.ts b/x-pack/plugins/uptime/server/lib/helper/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/index.ts rename to x-pack/plugins/uptime/server/lib/helper/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/make_date_rate_filter.ts b/x-pack/plugins/uptime/server/lib/helper/make_date_rate_filter.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/make_date_rate_filter.ts rename to x-pack/plugins/uptime/server/lib/helper/make_date_rate_filter.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/helper/object_to_array.ts b/x-pack/plugins/uptime/server/lib/helper/object_to_array.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/helper/object_to_array.ts rename to x-pack/plugins/uptime/server/lib/helper/object_to_array.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/lib.ts b/x-pack/plugins/uptime/server/lib/lib.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/lib.ts rename to x-pack/plugins/uptime/server/lib/lib.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/__snapshots__/extract_filter_aggs_results.test.ts.snap b/x-pack/plugins/uptime/server/lib/requests/__tests__/__snapshots__/extract_filter_aggs_results.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/__snapshots__/extract_filter_aggs_results.test.ts.snap rename to x-pack/plugins/uptime/server/lib/requests/__tests__/__snapshots__/extract_filter_aggs_results.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/__snapshots__/generate_filter_aggs.test.ts.snap b/x-pack/plugins/uptime/server/lib/requests/__tests__/__snapshots__/generate_filter_aggs.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/__snapshots__/generate_filter_aggs.test.ts.snap rename to x-pack/plugins/uptime/server/lib/requests/__tests__/__snapshots__/generate_filter_aggs.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/__snapshots__/get_monitor_charts.test.ts.snap b/x-pack/plugins/uptime/server/lib/requests/__tests__/__snapshots__/get_monitor_charts.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/__snapshots__/get_monitor_charts.test.ts.snap rename to x-pack/plugins/uptime/server/lib/requests/__tests__/__snapshots__/get_monitor_charts.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/__snapshots__/get_ping_histogram.test.ts.snap b/x-pack/plugins/uptime/server/lib/requests/__tests__/__snapshots__/get_ping_histogram.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/__snapshots__/get_ping_histogram.test.ts.snap rename to x-pack/plugins/uptime/server/lib/requests/__tests__/__snapshots__/get_ping_histogram.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/combine_range_with_filters.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/combine_range_with_filters.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/combine_range_with_filters.test.ts rename to x-pack/plugins/uptime/server/lib/requests/__tests__/combine_range_with_filters.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/extract_filter_aggs_results.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/extract_filter_aggs_results.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/extract_filter_aggs_results.test.ts rename to x-pack/plugins/uptime/server/lib/requests/__tests__/extract_filter_aggs_results.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/generate_filter_aggs.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/generate_filter_aggs.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/generate_filter_aggs.test.ts rename to x-pack/plugins/uptime/server/lib/requests/__tests__/generate_filter_aggs.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts rename to x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts rename to x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts rename to x-pack/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts rename to x-pack/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/monitor_charts_mock.json b/x-pack/plugins/uptime/server/lib/requests/__tests__/monitor_charts_mock.json similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/__tests__/monitor_charts_mock.json rename to x-pack/plugins/uptime/server/lib/requests/__tests__/monitor_charts_mock.json diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/generate_filter_aggs.ts b/x-pack/plugins/uptime/server/lib/requests/generate_filter_aggs.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/generate_filter_aggs.ts rename to x-pack/plugins/uptime/server/lib/requests/generate_filter_aggs.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_filter_bar.ts b/x-pack/plugins/uptime/server/lib/requests/get_filter_bar.ts similarity index 94% rename from x-pack/legacy/plugins/uptime/server/lib/requests/get_filter_bar.ts rename to x-pack/plugins/uptime/server/lib/requests/get_filter_bar.ts index 79259afe2b9eb..affe205a46844 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_filter_bar.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_filter_bar.ts @@ -5,9 +5,9 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { OverviewFilters } from '../../../common/runtime_types'; +import { OverviewFilters } from '../../../../../legacy/plugins/uptime/common/runtime_types'; import { generateFilterAggs } from './generate_filter_aggs'; -import { INDEX_NAMES } from '../../../common/constants'; +import { INDEX_NAMES } from '../../../../../legacy/plugins/uptime/common/constants'; export interface GetFilterBarParams { /** @param dateRangeStart timestamp bounds */ diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_index_pattern.ts b/x-pack/plugins/uptime/server/lib/requests/get_index_pattern.ts similarity index 92% rename from x-pack/legacy/plugins/uptime/server/lib/requests/get_index_pattern.ts rename to x-pack/plugins/uptime/server/lib/requests/get_index_pattern.ts index 4b40f800b6779..1ba1eb62e8439 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_index_pattern.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_index_pattern.ts @@ -6,8 +6,8 @@ import { APICaller } from 'src/core/server'; import { UMElasticsearchQueryFn } from '../adapters'; -import { IndexPatternsFetcher, IIndexPattern } from '../../../../../../../src/plugins/data/server'; -import { INDEX_NAMES } from '../../../common/constants'; +import { IndexPatternsFetcher, IIndexPattern } from '../../../../../../src/plugins/data/server'; +import { INDEX_NAMES } from '../../../../../legacy/plugins/uptime/common/constants'; export const getUptimeIndexPattern: UMElasticsearchQueryFn = async callES => { const indexPatternsFetcher = new IndexPatternsFetcher((...rest: Parameters) => diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_index_status.ts b/x-pack/plugins/uptime/server/lib/requests/get_index_status.ts similarity index 76% rename from x-pack/legacy/plugins/uptime/server/lib/requests/get_index_status.ts rename to x-pack/plugins/uptime/server/lib/requests/get_index_status.ts index e801b05d057f4..95aa7eeef88e1 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_index_status.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_index_status.ts @@ -5,8 +5,8 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { StatesIndexStatus } from '../../../common/graphql/types'; -import { INDEX_NAMES } from '../../../common/constants'; +import { StatesIndexStatus } from '../../../../../legacy/plugins/uptime/common/graphql/types'; +import { INDEX_NAMES } from '../../../../../legacy/plugins/uptime/common/constants'; export const getIndexStatus: UMElasticsearchQueryFn<{}, StatesIndexStatus> = async ({ callES }) => { const { diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_latest_monitor.ts b/x-pack/plugins/uptime/server/lib/requests/get_latest_monitor.ts similarity index 91% rename from x-pack/legacy/plugins/uptime/server/lib/requests/get_latest_monitor.ts rename to x-pack/plugins/uptime/server/lib/requests/get_latest_monitor.ts index bfaee3f2bf7ee..2d549fce06884 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_latest_monitor.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_latest_monitor.ts @@ -5,8 +5,8 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { Ping } from '../../../common/graphql/types'; -import { INDEX_NAMES } from '../../../common/constants'; +import { Ping } from '../../../../../legacy/plugins/uptime/common/graphql/types'; +import { INDEX_NAMES } from '../../../../../legacy/plugins/uptime/common/constants'; export interface GetLatestMonitorParams { /** @member dateRangeStart timestamp bounds */ diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor.ts b/x-pack/plugins/uptime/server/lib/requests/get_monitor.ts similarity index 87% rename from x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor.ts rename to x-pack/plugins/uptime/server/lib/requests/get_monitor.ts index 94175616f374e..20103042f19ab 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_monitor.ts @@ -5,8 +5,8 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { Ping } from '../../../common/graphql/types'; -import { INDEX_NAMES } from '../../../common/constants'; +import { Ping } from '../../../../../legacy/plugins/uptime/common/graphql/types'; +import { INDEX_NAMES } from '../../../../../legacy/plugins/uptime/common/constants'; export interface GetMonitorParams { /** @member monitorId optional limit to monitorId */ diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor_charts.ts b/x-pack/plugins/uptime/server/lib/requests/get_monitor_charts.ts similarity index 96% rename from x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor_charts.ts rename to x-pack/plugins/uptime/server/lib/requests/get_monitor_charts.ts index b97cc7287e921..7dd17ef9aa80f 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor_charts.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_monitor_charts.ts @@ -5,9 +5,12 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { INDEX_NAMES } from '../../../common/constants'; +import { INDEX_NAMES } from '../../../../../legacy/plugins/uptime/common/constants'; import { getHistogramIntervalFormatted } from '../helper'; -import { MonitorChart, LocationDurationLine } from '../../../common/graphql/types'; +import { + MonitorChart, + LocationDurationLine, +} from '../../../../../legacy/plugins/uptime/common/graphql/types'; export interface GetMonitorChartsParams { /** @member monitorId ID value for the selected monitor */ diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor_details.ts b/x-pack/plugins/uptime/server/lib/requests/get_monitor_details.ts similarity index 88% rename from x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor_details.ts rename to x-pack/plugins/uptime/server/lib/requests/get_monitor_details.ts index b516fde1ce844..eb3657e60a7bb 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor_details.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_monitor_details.ts @@ -5,8 +5,11 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { MonitorDetails, MonitorError } from '../../../common/runtime_types'; -import { INDEX_NAMES } from '../../../common/constants'; +import { + MonitorDetails, + MonitorError, +} from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { INDEX_NAMES } from '../../../../../legacy/plugins/uptime/common/constants'; export interface GetMonitorDetailsParams { monitorId: string; diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor_locations.ts b/x-pack/plugins/uptime/server/lib/requests/get_monitor_locations.ts similarity index 92% rename from x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor_locations.ts rename to x-pack/plugins/uptime/server/lib/requests/get_monitor_locations.ts index e1a0e14fe951d..328ef54c404d3 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor_locations.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_monitor_locations.ts @@ -5,8 +5,14 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { INDEX_NAMES, UNNAMED_LOCATION } from '../../../common/constants'; -import { MonitorLocations, MonitorLocation } from '../../../common/runtime_types'; +import { + INDEX_NAMES, + UNNAMED_LOCATION, +} from '../../../../../legacy/plugins/uptime/common/constants'; +import { + MonitorLocations, + MonitorLocation, +} from '../../../../../legacy/plugins/uptime/common/runtime_types'; /** * Fetch data for the monitor page title. diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor_states.ts b/x-pack/plugins/uptime/server/lib/requests/get_monitor_states.ts similarity index 89% rename from x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor_states.ts rename to x-pack/plugins/uptime/server/lib/requests/get_monitor_states.ts index 32c82b1fa2098..5b02e2502a27e 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_monitor_states.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_monitor_states.ts @@ -4,10 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CONTEXT_DEFAULTS } from '../../../common/constants'; +import { CONTEXT_DEFAULTS } from '../../../../../legacy/plugins/uptime/common/constants'; import { fetchPage } from './search'; import { UMElasticsearchQueryFn } from '../adapters'; -import { MonitorSummary, SortOrder, CursorDirection } from '../../../common/graphql/types'; +import { + MonitorSummary, + SortOrder, + CursorDirection, +} from '../../../../../legacy/plugins/uptime/common/graphql/types'; import { QueryContext } from './search'; export interface CursorPagination { diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_ping_histogram.ts b/x-pack/plugins/uptime/server/lib/requests/get_ping_histogram.ts similarity index 93% rename from x-pack/legacy/plugins/uptime/server/lib/requests/get_ping_histogram.ts rename to x-pack/plugins/uptime/server/lib/requests/get_ping_histogram.ts index 7b8ca4708255c..339409b63a4f6 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_ping_histogram.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_ping_histogram.ts @@ -5,10 +5,10 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; +import { INDEX_NAMES, QUERY } from '../../../../../legacy/plugins/uptime/common/constants'; import { getFilterClause } from '../helper'; -import { INDEX_NAMES, QUERY } from '../../../common/constants'; import { HistogramQueryResult } from './types'; -import { HistogramResult } from '../../../common/types'; +import { HistogramResult } from '../../../../../legacy/plugins/uptime/common/types'; export interface GetPingHistogramParams { /** @member dateRangeStart timestamp bounds */ diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_pings.ts b/x-pack/plugins/uptime/server/lib/requests/get_pings.ts similarity index 93% rename from x-pack/legacy/plugins/uptime/server/lib/requests/get_pings.ts rename to x-pack/plugins/uptime/server/lib/requests/get_pings.ts index 381aca720dc1d..ddca27d782066 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_pings.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_pings.ts @@ -5,8 +5,12 @@ */ import { UMElasticsearchQueryFn } from '../adapters/framework'; -import { PingResults, Ping, HttpBody } from '../../../common/graphql/types'; -import { INDEX_NAMES } from '../../../common/constants'; +import { + PingResults, + Ping, + HttpBody, +} from '../../../../../legacy/plugins/uptime/common/graphql/types'; +import { INDEX_NAMES } from '../../../../../legacy/plugins/uptime/common/constants'; export interface GetPingsParams { /** @member dateRangeStart timestamp bounds */ diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/get_snapshot_counts.ts b/x-pack/plugins/uptime/server/lib/requests/get_snapshot_counts.ts similarity index 96% rename from x-pack/legacy/plugins/uptime/server/lib/requests/get_snapshot_counts.ts rename to x-pack/plugins/uptime/server/lib/requests/get_snapshot_counts.ts index 8d84c0f4d6769..050e906f01c62 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/get_snapshot_counts.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_snapshot_counts.ts @@ -5,9 +5,12 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { Snapshot } from '../../../common/runtime_types'; +import { Snapshot } from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { + CONTEXT_DEFAULTS, + INDEX_NAMES, +} from '../../../../../legacy/plugins/uptime/common/constants'; import { QueryContext } from './search'; -import { CONTEXT_DEFAULTS, INDEX_NAMES } from '../../../common/constants'; export interface GetSnapshotCountParams { dateRangeStart: string; diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/index.ts b/x-pack/plugins/uptime/server/lib/requests/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/index.ts rename to x-pack/plugins/uptime/server/lib/requests/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/fetch_page.test.ts b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/fetch_page.test.ts similarity index 96% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/fetch_page.test.ts rename to x-pack/plugins/uptime/server/lib/requests/search/__tests__/fetch_page.test.ts index d519a4e75463f..f542773f32796 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/fetch_page.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/fetch_page.test.ts @@ -12,7 +12,7 @@ import { MonitorGroupsPage, } from '../fetch_page'; import { QueryContext } from '../query_context'; -import { MonitorSummary } from '../../../../../common/graphql/types'; +import { MonitorSummary } from '../../../../../../../legacy/plugins/uptime/common/graphql/types'; import { nextPagination, prevPagination, simpleQueryContext } from './test_helpers'; const simpleFixture: MonitorGroups[] = [ diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/monitor_group_iterator.test.ts b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/monitor_group_iterator.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/monitor_group_iterator.test.ts rename to x-pack/plugins/uptime/server/lib/requests/search/__tests__/monitor_group_iterator.test.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/query_context.test.ts b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/query_context.test.ts similarity index 95% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/query_context.test.ts rename to x-pack/plugins/uptime/server/lib/requests/search/__tests__/query_context.test.ts index 86506c2c4c044..ea81ec623e01c 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/query_context.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/query_context.test.ts @@ -6,7 +6,10 @@ import { QueryContext } from '../query_context'; import { CursorPagination } from '../types'; -import { CursorDirection, SortOrder } from '../../../../../common/graphql/types'; +import { + CursorDirection, + SortOrder, +} from '../../../../../../../legacy/plugins/uptime/common/graphql/types'; describe(QueryContext, () => { // 10 minute range diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/test_helpers.ts b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/test_helpers.ts similarity index 88% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/test_helpers.ts rename to x-pack/plugins/uptime/server/lib/requests/search/__tests__/test_helpers.ts index 98b192d14f91a..d96f8dc95aa72 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/search/__tests__/test_helpers.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/test_helpers.ts @@ -5,7 +5,10 @@ */ import { CursorPagination } from '../types'; -import { CursorDirection, SortOrder } from '../../../../../common/graphql/types'; +import { + CursorDirection, + SortOrder, +} from '../../../../../../../legacy/plugins/uptime/common/graphql/types'; import { QueryContext } from '../query_context'; export const prevPagination = (key: any): CursorPagination => { diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/enrich_monitor_groups.ts b/x-pack/plugins/uptime/server/lib/requests/search/enrich_monitor_groups.ts similarity index 98% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/enrich_monitor_groups.ts rename to x-pack/plugins/uptime/server/lib/requests/search/enrich_monitor_groups.ts index e37c749e63566..9ad3928a3b1b2 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/search/enrich_monitor_groups.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/enrich_monitor_groups.ts @@ -7,14 +7,14 @@ import { get, sortBy } from 'lodash'; import { QueryContext } from './query_context'; import { getHistogramIntervalFormatted } from '../../helper'; -import { INDEX_NAMES, STATES } from '../../../../common/constants'; +import { INDEX_NAMES, STATES } from '../../../../../../legacy/plugins/uptime/common/constants'; import { MonitorSummary, SummaryHistogram, Check, CursorDirection, SortOrder, -} from '../../../../common/graphql/types'; +} from '../../../../../../legacy/plugins/uptime/common/graphql/types'; import { MonitorEnricher } from './fetch_page'; export const enrichMonitorGroups: MonitorEnricher = async ( diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/fetch_chunk.ts b/x-pack/plugins/uptime/server/lib/requests/search/fetch_chunk.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/fetch_chunk.ts rename to x-pack/plugins/uptime/server/lib/requests/search/fetch_chunk.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/fetch_page.ts b/x-pack/plugins/uptime/server/lib/requests/search/fetch_page.ts similarity index 96% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/fetch_page.ts rename to x-pack/plugins/uptime/server/lib/requests/search/fetch_page.ts index 6440850dc0ffc..62144dacbd377 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/search/fetch_page.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/fetch_page.ts @@ -7,8 +7,12 @@ import { flatten } from 'lodash'; import { CursorPagination } from './types'; import { QueryContext } from './query_context'; -import { QUERY } from '../../../../common/constants'; -import { CursorDirection, MonitorSummary, SortOrder } from '../../../../common/graphql/types'; +import { QUERY } from '../../../../../../legacy/plugins/uptime/common/constants'; +import { + CursorDirection, + MonitorSummary, + SortOrder, +} from '../../../../../../legacy/plugins/uptime/common/graphql/types'; import { enrichMonitorGroups } from './enrich_monitor_groups'; import { MonitorGroupIterator } from './monitor_group_iterator'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/find_potential_matches.ts b/x-pack/plugins/uptime/server/lib/requests/search/find_potential_matches.ts similarity index 95% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/find_potential_matches.ts rename to x-pack/plugins/uptime/server/lib/requests/search/find_potential_matches.ts index fc0e35b279e0b..9b3b1186472be 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/search/find_potential_matches.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/find_potential_matches.ts @@ -5,8 +5,8 @@ */ import { get, set } from 'lodash'; -import { CursorDirection } from '../../../../common/graphql/types'; -import { INDEX_NAMES } from '../../../../common/constants'; +import { CursorDirection } from '../../../../../../legacy/plugins/uptime/common/graphql/types'; +import { INDEX_NAMES } from '../../../../../../legacy/plugins/uptime/common/constants'; import { QueryContext } from './query_context'; // This is the first phase of the query. In it, we find the most recent check groups that matched the given query. diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/index.ts b/x-pack/plugins/uptime/server/lib/requests/search/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/index.ts rename to x-pack/plugins/uptime/server/lib/requests/search/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/monitor_group_iterator.ts b/x-pack/plugins/uptime/server/lib/requests/search/monitor_group_iterator.ts similarity index 98% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/monitor_group_iterator.ts rename to x-pack/plugins/uptime/server/lib/requests/search/monitor_group_iterator.ts index ced557dbf62e0..267551907c5e8 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/search/monitor_group_iterator.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/monitor_group_iterator.ts @@ -6,7 +6,7 @@ import { QueryContext } from './query_context'; import { fetchChunk } from './fetch_chunk'; -import { CursorDirection } from '../../../../common/graphql/types'; +import { CursorDirection } from '../../../../../../legacy/plugins/uptime/common/graphql/types'; import { MonitorGroups } from './fetch_page'; import { CursorPagination } from './types'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/query_context.ts b/x-pack/plugins/uptime/server/lib/requests/search/query_context.ts similarity index 97% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/query_context.ts rename to x-pack/plugins/uptime/server/lib/requests/search/query_context.ts index f5b13c165d87d..c1f5d89ec1a38 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/search/query_context.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/query_context.ts @@ -6,7 +6,7 @@ import moment from 'moment'; import { APICaller } from 'src/core/server'; -import { INDEX_NAMES } from '../../../../common/constants'; +import { INDEX_NAMES } from '../../../../../../legacy/plugins/uptime/common/constants'; import { CursorPagination } from './types'; import { parseRelativeDate } from '../../helper'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts b/x-pack/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts similarity index 96% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts rename to x-pack/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts index a55301555c8bf..c55aff3e8c4cd 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { INDEX_NAMES } from '../../../../common/constants'; +import { INDEX_NAMES } from '../../../../../../legacy/plugins/uptime/common/constants'; import { QueryContext } from './query_context'; -import { CursorDirection } from '../../../../common/graphql/types'; +import { CursorDirection } from '../../../../../../legacy/plugins/uptime/common/graphql/types'; import { MonitorGroups, MonitorLocCheckGroup } from './fetch_page'; /** diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/search/types.ts b/x-pack/plugins/uptime/server/lib/requests/search/types.ts similarity index 76% rename from x-pack/legacy/plugins/uptime/server/lib/requests/search/types.ts rename to x-pack/plugins/uptime/server/lib/requests/search/types.ts index dc6021a91146a..42c98ace6e8f5 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/search/types.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/types.ts @@ -4,7 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CursorDirection, SortOrder } from '../../../../common/graphql/types'; +import { + CursorDirection, + SortOrder, +} from '../../../../../../legacy/plugins/uptime/common/graphql/types'; export interface CursorPagination { cursorKey?: any; diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/types.ts b/x-pack/plugins/uptime/server/lib/requests/types.ts similarity index 89% rename from x-pack/legacy/plugins/uptime/server/lib/requests/types.ts rename to x-pack/plugins/uptime/server/lib/requests/types.ts index e17eb546712a9..53a4e989e3789 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/types.ts +++ b/x-pack/plugins/uptime/server/lib/requests/types.ts @@ -4,9 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Ping, PingResults } from '../../../common/graphql/types'; +import { Ping, PingResults } from '../../../../../legacy/plugins/uptime/common/graphql/types'; import { UMElasticsearchQueryFn } from '../adapters'; -import { GetPingHistogramParams, HistogramResult } from '../../../common/types'; +import { + GetPingHistogramParams, + HistogramResult, +} from '../../../../../legacy/plugins/uptime/common/types'; export interface GetAllParams { /** @member dateRangeStart timestamp bounds */ diff --git a/x-pack/legacy/plugins/uptime/server/lib/requests/uptime_requests.ts b/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts similarity index 83% rename from x-pack/legacy/plugins/uptime/server/lib/requests/uptime_requests.ts rename to x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts index 73be850306202..8a411368c228f 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/requests/uptime_requests.ts +++ b/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts @@ -5,7 +5,12 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { Ping, MonitorChart, PingResults, StatesIndexStatus } from '../../../common/graphql/types'; +import { + Ping, + MonitorChart, + PingResults, + StatesIndexStatus, +} from '../../../../../legacy/plugins/uptime/common/graphql/types'; import { GetFilterBarParams, GetLatestMonitorParams, @@ -22,10 +27,10 @@ import { MonitorDetails, MonitorLocations, Snapshot, -} from '../../../common/runtime_types'; +} from '../../../../../legacy/plugins/uptime/common/runtime_types'; import { GetMonitorStatesResult } from './get_monitor_states'; import { GetSnapshotCountParams } from './get_snapshot_counts'; -import { HistogramResult } from '../../../common/types'; +import { HistogramResult } from '../../../../../legacy/plugins/uptime/common/types'; type ESQ = UMElasticsearchQueryFn; diff --git a/x-pack/plugins/uptime/server/plugin.ts b/x-pack/plugins/uptime/server/plugin.ts new file mode 100644 index 0000000000000..e217b0e2f1ad8 --- /dev/null +++ b/x-pack/plugins/uptime/server/plugin.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { PluginInitializerContext, CoreStart, CoreSetup } from '../../../../src/core/server'; +import { initServerWithKibana } from './kibana.index'; +import { UptimeCorePlugins } from './lib/adapters'; + +export class Plugin { + constructor(_initializerContext: PluginInitializerContext) {} + public setup(core: CoreSetup, plugins: UptimeCorePlugins) { + initServerWithKibana({ route: core.http.createRouter() }, plugins); + } + public start(_core: CoreStart, _plugins: any) {} +} diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/create_route_with_auth.ts b/x-pack/plugins/uptime/server/rest_api/create_route_with_auth.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/create_route_with_auth.ts rename to x-pack/plugins/uptime/server/rest_api/create_route_with_auth.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/index.ts b/x-pack/plugins/uptime/server/rest_api/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/index.ts rename to x-pack/plugins/uptime/server/rest_api/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts b/x-pack/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts rename to x-pack/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/index.ts b/x-pack/plugins/uptime/server/rest_api/index_pattern/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/index.ts rename to x-pack/plugins/uptime/server/rest_api/index_pattern/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/monitors/index.ts b/x-pack/plugins/uptime/server/rest_api/monitors/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/monitors/index.ts rename to x-pack/plugins/uptime/server/rest_api/monitors/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/monitors/monitor_locations.ts b/x-pack/plugins/uptime/server/rest_api/monitors/monitor_locations.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/monitors/monitor_locations.ts rename to x-pack/plugins/uptime/server/rest_api/monitors/monitor_locations.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/monitors/monitors_details.ts b/x-pack/plugins/uptime/server/rest_api/monitors/monitors_details.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/monitors/monitors_details.ts rename to x-pack/plugins/uptime/server/rest_api/monitors/monitors_details.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/monitors/status.ts b/x-pack/plugins/uptime/server/rest_api/monitors/status.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/monitors/status.ts rename to x-pack/plugins/uptime/server/rest_api/monitors/status.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/overview_filters/get_overview_filters.ts b/x-pack/plugins/uptime/server/rest_api/overview_filters/get_overview_filters.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/overview_filters/get_overview_filters.ts rename to x-pack/plugins/uptime/server/rest_api/overview_filters/get_overview_filters.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/overview_filters/index.ts b/x-pack/plugins/uptime/server/rest_api/overview_filters/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/overview_filters/index.ts rename to x-pack/plugins/uptime/server/rest_api/overview_filters/index.ts diff --git a/x-pack/plugins/uptime/server/rest_api/pings/get_all.ts b/x-pack/plugins/uptime/server/rest_api/pings/get_all.ts new file mode 100644 index 0000000000000..21168edfc9744 --- /dev/null +++ b/x-pack/plugins/uptime/server/rest_api/pings/get_all.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; +import { UMServerLibs } from '../../lib/lib'; +import { UMRestApiRouteFactory } from '../types'; + +export const createGetAllRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ + method: 'GET', + path: '/api/uptime/pings', + validate: { + query: schema.object({ + dateRangeStart: schema.string(), + dateRangeEnd: schema.string(), + location: schema.maybe(schema.string()), + monitorId: schema.maybe(schema.string()), + size: schema.maybe(schema.number()), + sort: schema.maybe(schema.string()), + status: schema.maybe(schema.string()), + }), + }, + options: { + tags: ['access:uptime'], + }, + handler: async ({ callES }, _context, request, response): Promise => { + const { dateRangeStart, dateRangeEnd, location, monitorId, size, sort, status } = request.query; + + const result = await libs.requests.getPings({ + callES, + dateRangeStart, + dateRangeEnd, + monitorId, + status, + sort, + size, + location, + }); + + return response.ok({ + body: { + ...result, + }, + }); + }, +}); diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts b/x-pack/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts rename to x-pack/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/pings/get_pings.ts b/x-pack/plugins/uptime/server/rest_api/pings/get_pings.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/pings/get_pings.ts rename to x-pack/plugins/uptime/server/rest_api/pings/get_pings.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/pings/index.ts b/x-pack/plugins/uptime/server/rest_api/pings/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/pings/index.ts rename to x-pack/plugins/uptime/server/rest_api/pings/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts b/x-pack/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts rename to x-pack/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/snapshot/index.ts b/x-pack/plugins/uptime/server/rest_api/snapshot/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/snapshot/index.ts rename to x-pack/plugins/uptime/server/rest_api/snapshot/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/telemetry/index.ts b/x-pack/plugins/uptime/server/rest_api/telemetry/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/telemetry/index.ts rename to x-pack/plugins/uptime/server/rest_api/telemetry/index.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/telemetry/log_monitor_page.ts b/x-pack/plugins/uptime/server/rest_api/telemetry/log_monitor_page.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/telemetry/log_monitor_page.ts rename to x-pack/plugins/uptime/server/rest_api/telemetry/log_monitor_page.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/telemetry/log_overview_page.ts b/x-pack/plugins/uptime/server/rest_api/telemetry/log_overview_page.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/telemetry/log_overview_page.ts rename to x-pack/plugins/uptime/server/rest_api/telemetry/log_overview_page.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/types.ts b/x-pack/plugins/uptime/server/rest_api/types.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/types.ts rename to x-pack/plugins/uptime/server/rest_api/types.ts diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/uptime_route_wrapper.ts b/x-pack/plugins/uptime/server/rest_api/uptime_route_wrapper.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/rest_api/uptime_route_wrapper.ts rename to x-pack/plugins/uptime/server/rest_api/uptime_route_wrapper.ts diff --git a/x-pack/legacy/plugins/uptime/server/uptime_server.ts b/x-pack/plugins/uptime/server/uptime_server.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/server/uptime_server.ts rename to x-pack/plugins/uptime/server/uptime_server.ts diff --git a/x-pack/test/api_integration/apis/uptime/rest/ping_histogram.ts b/x-pack/test/api_integration/apis/uptime/rest/ping_histogram.ts index 429f50ec0aa5b..0982d5fef7cb4 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/ping_histogram.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/ping_histogram.ts @@ -6,7 +6,7 @@ import { expectFixtureEql } from '../graphql/helpers/expect_fixture_eql'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { assertCloseTo } from '../../../../../legacy/plugins/uptime/server/lib/helper'; +import { assertCloseTo } from '../../../../../plugins/uptime/server/lib/helper'; export default function({ getService }: FtrProviderContext) { describe('pingHistogram', () => { From 899270a108c5e47f5602c0f5c3b67a8502e47173 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 25 Feb 2020 15:31:04 +0100 Subject: [PATCH 055/123] [Upgrade Assistant] Move out of legacy folder (#58034) * Create x-pack/plugins skeleton for upgrade assistant * Move public folder contents Move the public folder of Upgrade Assistant and migrate public to use HttpSetup (remove axios) * Include stylesheets in public * Move server side out of legacy Begin migration of Reindex worker to new platform Move imports around so that it satsifies new platform constraints like not importing server side code (even types) in client. * Updated the routes with new dependencies and removed server shim * Fix router unit tests * Fix server lib tests After changing function signatures for the reindex server factory (and others) all of the tests needed to be revisited and brought in line with the new APIs. Also used core/server mocks where appropriate * Clean up types issues * Fix setting credentials on request header * Removed the security plugin from Upgrade Assistant The security plugin is a potential future consumer of the Upgrade Assistant's deprecation feature and we would therefore not want to create a circular depedency here. We pull in the licensing plugin rather (as it is less likely that we will depend on that) and use it to determine whether security is available and enabled. * Migrate to config to new platform config xpack.upgrade_assistant.enabled * Remove unused types * Fix import issue * Move upgrade assistant back to Elasticsearch management section * Update dotfiles Added elasticsearch ui team as upgrade assistant code owner Updated i18nrc.json path * Alphabetical ordering in xpack/i18nrc.json * Implemented PR feedback Renamed callCluster -> callAsUser to be more consistent with platform naming. Added comment about why we are not using security plugin directly inside of Upgrade Assistant. Fixed long path imports and use 'src/core/..' throughout. Fixed import ordering. Renamed variables inside of telemetry lib. * Revert to longer import path In plugin.ts importing from 'kibana/server' or 'src/core/server' results in a module not found error. Co-authored-by: Elastic Machine --- .github/CODEOWNERS | 2 + x-pack/.i18nrc.json | 2 +- .../legacy/plugins/upgrade_assistant/index.ts | 44 +--- .../plugins/upgrade_assistant/public/index.ts | 7 - .../upgrade_assistant/public/legacy.ts | 106 --------- .../public/np_ready/application/app.tsx | 40 ---- .../reindex/polling_service.test.mocks.ts | 24 -- .../public/np_ready/plugin.ts | 24 -- .../plugins/upgrade_assistant/server/index.ts | 7 - .../np_ready/lib/telemetry/es_ui_open_apis.ts | 47 ---- .../lib/telemetry/es_ui_reindex_apis.ts | 58 ----- .../server/np_ready/plugin.ts | 49 ---- .../server/np_ready/routes/cluster_checkup.ts | 46 ---- .../np_ready/routes/create_request_shim.ts | 16 -- .../np_ready/routes/deprecation_logging.ts | 57 ----- .../server/np_ready/routes/reindex_indices.ts | 207 ----------------- .../server/np_ready/types.ts | 29 --- .../upgrade_assistant/common/config.ts} | 10 +- .../plugins/upgrade_assistant/common/types.ts | 13 ++ .../upgrade_assistant/common/version.ts | 0 x-pack/plugins/upgrade_assistant/kibana.json | 9 + .../public/application/_index.scss} | 0 .../public/application/app.tsx | 44 ++++ .../public}/application/app_context.tsx | 1 - .../application/components/_index.scss | 0 .../application/components/error_banner.tsx | 0 .../components/latest_minor_banner.tsx | 2 +- .../application/components/tabs.test.tsx | 28 +-- .../public}/application/components/tabs.tsx | 9 +- .../__fixtures__/checkup_api_response.json | 0 .../__snapshots__/checkup_tab.test.tsx.snap | 0 .../__snapshots__/filter_bar.test.tsx.snap | 0 .../__snapshots__/group_by_bar.test.tsx.snap | 0 .../components/tabs/checkup/_index.scss | 0 .../tabs/checkup/checkup_tab.test.tsx | 0 .../components/tabs/checkup/checkup_tab.tsx | 2 +- .../components/tabs/checkup/constants.tsx | 0 .../components/tabs/checkup/controls.tsx | 0 .../tabs/checkup/deprecations/_cell.scss | 0 .../checkup/deprecations/_deprecations.scss | 0 .../tabs/checkup/deprecations/_index.scss | 0 .../tabs/checkup/deprecations/cell.tsx | 4 +- .../checkup/deprecations/count_summary.tsx | 2 +- .../checkup/deprecations/grouped.test.tsx | 2 +- .../tabs/checkup/deprecations/grouped.tsx | 2 +- .../tabs/checkup/deprecations/health.tsx | 0 .../tabs/checkup/deprecations/index.tsx | 0 .../checkup/deprecations/index_table.test.tsx | 0 .../tabs/checkup/deprecations/index_table.tsx | 4 +- .../tabs/checkup/deprecations/list.test.tsx | 2 +- .../tabs/checkup/deprecations/list.tsx | 2 +- .../checkup/deprecations/reindex/_button.scss | 0 .../checkup/deprecations/reindex/_index.scss | 0 .../checkup/deprecations/reindex/button.tsx | 7 +- .../checklist_step.test.tsx.snap | 0 .../__snapshots__/warning_step.test.tsx.snap | 0 .../deprecations/reindex/flyout/_index.scss | 0 .../reindex/flyout/_step_progress.scss | 0 .../reindex/flyout/_warnings_step.scss | 0 .../reindex/flyout/checklist_step.test.tsx | 2 +- .../reindex/flyout/checklist_step.tsx | 2 +- .../deprecations/reindex/flyout/container.tsx | 0 .../deprecations/reindex/flyout/index.tsx | 0 .../reindex/flyout/progress.test.tsx | 2 +- .../deprecations/reindex/flyout/progress.tsx | 2 +- .../reindex/flyout/step_progress.tsx | 0 .../reindex/flyout/warning_step.test.tsx | 2 +- .../reindex/flyout/warnings_step.tsx | 2 +- .../checkup/deprecations/reindex/index.tsx | 0 .../reindex/polling_service.test.ts | 67 ++---- .../deprecations/reindex/polling_service.ts | 29 +-- .../tabs/checkup/filter_bar.test.tsx | 0 .../components/tabs/checkup/filter_bar.tsx | 0 .../tabs/checkup/group_by_bar.test.tsx | 0 .../components/tabs/checkup/group_by_bar.tsx | 0 .../components/tabs/checkup/index.tsx | 0 .../components/tabs/overview/_index.scss | 0 .../components/tabs/overview/_steps.scss | 0 .../overview/deprecation_logging_toggle.tsx | 25 +- .../components/tabs/overview/index.tsx | 2 +- .../components/tabs/overview/steps.tsx | 6 +- .../public}/application/components/types.ts | 5 +- .../public/application/render_app.tsx | 20 ++ .../public}/application/utils.test.ts | 0 .../public}/application/utils.ts | 0 .../upgrade_assistant/public/index.scss | 1 + .../upgrade_assistant/public}/index.ts | 7 +- .../upgrade_assistant/public/plugin.ts | 48 ++++ .../plugins/upgrade_assistant/server/index.ts | 19 ++ .../lib/__fixtures__/fake_deprecations.json | 0 .../lib/__mocks__/es_version_precheck.ts | 0 .../es_migration_apis.test.ts.snap | 0 .../lib/es_deprecation_logging_apis.test.ts | 20 +- .../lib/es_deprecation_logging_apis.ts | 14 +- .../server}/lib/es_migration_apis.test.ts | 26 ++- .../server}/lib/es_migration_apis.ts | 27 +-- .../server}/lib/es_version_precheck.test.ts | 2 +- .../server}/lib/es_version_precheck.ts | 2 +- .../lib/reindexing/credential_store.test.ts | 2 +- .../lib/reindexing/credential_store.ts | 5 +- .../server}/lib/reindexing/index.ts | 0 .../lib/reindexing/index_settings.test.ts | 2 +- .../server}/lib/reindexing/index_settings.ts | 4 +- .../lib/reindexing/reindex_actions.test.ts | 4 +- .../server}/lib/reindexing/reindex_actions.ts | 9 +- .../lib/reindexing/reindex_service.test.ts | 93 ++++---- .../server}/lib/reindexing/reindex_service.ts | 70 +++--- .../server}/lib/reindexing/types.ts | 0 .../server}/lib/reindexing/worker.ts | 61 +++-- .../lib/telemetry/es_ui_open_apis.test.ts | 50 ++-- .../server/lib/telemetry/es_ui_open_apis.ts | 58 +++++ .../lib/telemetry/es_ui_reindex_apis.test.ts | 56 ++--- .../lib/telemetry/es_ui_reindex_apis.ts | 64 ++++++ .../server}/lib/telemetry/index.ts | 0 .../lib/telemetry/usage_collector.test.ts | 37 +-- .../server}/lib/telemetry/usage_collector.ts | 44 ++-- .../upgrade_assistant/server/plugin.ts | 125 ++++++++++ .../server}/routes/__mocks__/request.mock.ts | 2 +- .../server}/routes/__mocks__/routes.mock.ts | 16 +- .../server}/routes/cluster_checkup.test.ts | 44 ++-- .../server/routes/cluster_checkup.ts | 43 ++++ .../routes/deprecation_logging.test.ts | 52 +++-- .../server/routes/deprecation_logging.ts | 72 ++++++ .../server}/routes/reindex_indices.test.ts | 93 ++++---- .../server/routes/reindex_indices.ts | 217 ++++++++++++++++++ .../server}/routes/telemetry.test.ts | 58 +++-- .../server}/routes/telemetry.ts | 32 ++- .../plugins/upgrade_assistant/server/types.ts | 19 ++ .../upgrade_assistant/reindexing.js | 5 +- 129 files changed, 1234 insertions(+), 1343 deletions(-) delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/public/index.ts delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/public/legacy.ts delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/app.tsx delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/polling_service.test.mocks.ts delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/public/np_ready/plugin.ts delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/server/index.ts delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_open_apis.ts delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_reindex_apis.ts delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/server/np_ready/plugin.ts delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/cluster_checkup.ts delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/create_request_shim.ts delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/deprecation_logging.ts delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/reindex_indices.ts delete mode 100644 x-pack/legacy/plugins/upgrade_assistant/server/np_ready/types.ts rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready/index.ts => plugins/upgrade_assistant/common/config.ts} (54%) rename x-pack/{legacy => }/plugins/upgrade_assistant/common/types.ts (88%) rename x-pack/{legacy => }/plugins/upgrade_assistant/common/version.ts (100%) create mode 100644 x-pack/plugins/upgrade_assistant/kibana.json rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready/application/index.scss => plugins/upgrade_assistant/public/application/_index.scss} (100%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/app.tsx rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/app_context.tsx (98%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/_index.scss (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/error_banner.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/latest_minor_banner.tsx (98%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs.test.tsx (82%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs.tsx (96%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/__fixtures__/checkup_api_response.json (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/__snapshots__/checkup_tab.test.tsx.snap (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/__snapshots__/filter_bar.test.tsx.snap (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/__snapshots__/group_by_bar.test.tsx.snap (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/_index.scss (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/checkup_tab.test.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/checkup_tab.tsx (99%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/constants.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/controls.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/_cell.scss (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/_deprecations.scss (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/_index.scss (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/cell.tsx (94%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/count_summary.tsx (93%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/grouped.test.tsx (98%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/grouped.tsx (98%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/health.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/index.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/index_table.test.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/index_table.tsx (96%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/list.test.tsx (96%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/list.tsx (97%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/_button.scss (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/_index.scss (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/button.tsx (97%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/__snapshots__/checklist_step.test.tsx.snap (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/__snapshots__/warning_step.test.tsx.snap (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/_index.scss (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/_step_progress.scss (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/_warnings_step.scss (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/checklist_step.test.tsx (98%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/checklist_step.tsx (98%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/container.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/index.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/progress.test.tsx (99%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/progress.tsx (99%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/step_progress.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/warning_step.test.tsx (95%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/flyout/warnings_step.tsx (99%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/index.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/polling_service.test.ts (63%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/deprecations/reindex/polling_service.ts (82%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/filter_bar.test.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/filter_bar.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/group_by_bar.test.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/group_by_bar.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/checkup/index.tsx (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/overview/_index.scss (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/overview/_steps.scss (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/overview/deprecation_logging_toggle.tsx (86%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/overview/index.tsx (96%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/tabs/overview/steps.tsx (98%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/components/types.ts (89%) create mode 100644 x-pack/plugins/upgrade_assistant/public/application/render_app.tsx rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/utils.test.ts (100%) rename x-pack/{legacy/plugins/upgrade_assistant/public/np_ready => plugins/upgrade_assistant/public}/application/utils.ts (100%) create mode 100644 x-pack/plugins/upgrade_assistant/public/index.scss rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/public}/index.ts (62%) create mode 100644 x-pack/plugins/upgrade_assistant/public/plugin.ts create mode 100644 x-pack/plugins/upgrade_assistant/server/index.ts rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/__fixtures__/fake_deprecations.json (100%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/__mocks__/es_version_precheck.ts (100%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/__snapshots__/es_migration_apis.test.ts.snap (100%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/es_deprecation_logging_apis.test.ts (75%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/es_deprecation_logging_apis.ts (75%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/es_migration_apis.test.ts (73%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/es_migration_apis.ts (75%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/es_version_precheck.test.ts (98%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/es_version_precheck.ts (98%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/reindexing/credential_store.test.ts (95%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/reindexing/credential_store.ts (91%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/reindexing/index.ts (100%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/reindexing/index_settings.test.ts (99%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/reindexing/index_settings.ts (97%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/reindexing/reindex_actions.test.ts (99%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/reindexing/reindex_actions.ts (97%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/reindexing/reindex_service.test.ts (95%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/reindexing/reindex_service.ts (90%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/reindexing/types.ts (100%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/reindexing/worker.ts (76%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/telemetry/es_ui_open_apis.test.ts (51%) create mode 100644 x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.ts rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/telemetry/es_ui_reindex_apis.test.ts (52%) create mode 100644 x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.ts rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/telemetry/index.ts (100%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/telemetry/usage_collector.test.ts (78%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/lib/telemetry/usage_collector.ts (72%) create mode 100644 x-pack/plugins/upgrade_assistant/server/plugin.ts rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/routes/__mocks__/request.mock.ts (92%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/routes/__mocks__/routes.mock.ts (72%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/routes/cluster_checkup.test.ts (73%) create mode 100644 x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.ts rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/routes/deprecation_logging.test.ts (56%) create mode 100644 x-pack/plugins/upgrade_assistant/server/routes/deprecation_logging.ts rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/routes/reindex_indices.test.ts (80%) create mode 100644 x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.ts rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/routes/telemetry.test.ts (79%) rename x-pack/{legacy/plugins/upgrade_assistant/server/np_ready => plugins/upgrade_assistant/server}/routes/telemetry.ts (66%) create mode 100644 x-pack/plugins/upgrade_assistant/server/types.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 51433f598ac16..b924c7a1a2c29 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -179,6 +179,8 @@ /x-pack/legacy/plugins/rollup/ @elastic/es-ui /x-pack/plugins/searchprofiler/ @elastic/es-ui /x-pack/legacy/plugins/snapshot_restore/ @elastic/es-ui +/x-pack/legacy/plugins/upgrade_assistant/ @elastic/es-ui +/x-pack/plugins/upgrade_assistant/ @elastic/es-ui /x-pack/plugins/watcher/ @elastic/es-ui # Endpoint diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index b1cb9075434e8..bb084b3bb72a1 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -40,7 +40,7 @@ "xpack.taskManager": "legacy/plugins/task_manager", "xpack.transform": "legacy/plugins/transform", "xpack.triggersActionsUI": "plugins/triggers_actions_ui", - "xpack.upgradeAssistant": "legacy/plugins/upgrade_assistant", + "xpack.upgradeAssistant": "plugins/upgrade_assistant", "xpack.uptime": "legacy/plugins/uptime", "xpack.watcher": "plugins/watcher" }, diff --git a/x-pack/legacy/plugins/upgrade_assistant/index.ts b/x-pack/legacy/plugins/upgrade_assistant/index.ts index 3f98ff60a91ce..b5e8ce4750215 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/index.ts +++ b/x-pack/legacy/plugins/upgrade_assistant/index.ts @@ -3,25 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import _ from 'lodash'; -import Joi from 'joi'; import { Legacy } from 'kibana'; -import { resolve } from 'path'; import mappings from './mappings.json'; -import { plugin } from './server/np_ready'; -import { CloudSetup } from '../../../plugins/cloud/server'; export function upgradeAssistant(kibana: any) { - const publicSrc = resolve(__dirname, 'public'); - const npSrc = resolve(publicSrc, 'np_ready'); - const config: Legacy.PluginSpecOptions = { id: 'upgrade_assistant', - configPrefix: 'xpack.upgrade_assistant', - require: ['elasticsearch'], uiExports: { // @ts-ignore - managementSections: ['plugins/upgrade_assistant'], savedObjectSchemas: { 'upgrade-assistant-reindex-operation': { isNamespaceAgnostic: true, @@ -30,41 +19,10 @@ export function upgradeAssistant(kibana: any) { isNamespaceAgnostic: true, }, }, - styleSheetPaths: resolve(npSrc, 'application/index.scss'), mappings, }, - publicDir: publicSrc, - - config() { - return Joi.object({ - enabled: Joi.boolean().default(true), - }).default(); - }, - - init(server: Legacy.Server) { - // Add server routes and initialize the plugin here - const instance = plugin({} as any); - const { usageCollection, cloud } = server.newPlatform.setup.plugins; - instance.setup(server.newPlatform.setup.core, { - usageCollection, - cloud: cloud as CloudSetup, - __LEGACY: { - // Legacy objects - events: server.events, - savedObjects: server.savedObjects, - - // Legacy functions - log: server.log.bind(server), - - // Legacy plugins - plugins: { - elasticsearch: server.plugins.elasticsearch, - xpack_main: server.plugins.xpack_main, - }, - }, - }); - }, + init() {}, }; return new kibana.Plugin(config); } diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/index.ts b/x-pack/legacy/plugins/upgrade_assistant/public/index.ts deleted file mode 100644 index d22b5d64b6b46..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/public/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export * from './legacy'; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/legacy.ts b/x-pack/legacy/plugins/upgrade_assistant/public/legacy.ts deleted file mode 100644 index b6bc6a14de224..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/public/legacy.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { ComponentType } from 'react'; -import { i18n } from '@kbn/i18n'; - -/* LEGACY IMPORTS */ -import { npSetup } from 'ui/new_platform'; -import { wrapInI18nContext } from 'ui/i18n'; -import { management } from 'ui/management'; -// @ts-ignore -import { uiModules } from 'ui/modules'; -import routes from 'ui/routes'; -import chrome from 'ui/chrome'; -/* LEGACY IMPORTS */ - -import { NEXT_MAJOR_VERSION } from '../common/version'; -import { plugin } from './np_ready'; -import { CloudSetup } from '../../../../plugins/cloud/public'; - -const BASE_PATH = `/management/elasticsearch/upgrade_assistant`; - -export interface LegacyAppMountParameters { - __LEGACY: { renderToElement: (RootComponent: ComponentType) => void }; -} - -export interface LegacyApp { - mount(ctx: any, params: LegacyAppMountParameters): void; -} - -export interface LegacyManagementPlugin { - sections: { - get( - name: string - ): { - registerApp(app: LegacyApp): void; - }; - }; -} - -// Based on /rfcs/text/0006_management_section_service.md -export interface LegacyPlugins { - cloud?: CloudSetup; - management: LegacyManagementPlugin; - __LEGACY: { - XSRF: string; - }; -} - -function startApp() { - routes.when(`${BASE_PATH}/:view?`, { - template: - '', - }); - const { cloud } = npSetup.plugins as any; - const legacyPluginsShim: LegacyPlugins = { - cloud: cloud as CloudSetup, - __LEGACY: { - XSRF: chrome.getXsrfToken(), - }, - management: { - sections: { - get(_: string) { - return { - registerApp(app) { - management.getSection('elasticsearch').register('upgrade_assistant', { - visible: true, - display: i18n.translate('xpack.upgradeAssistant.appTitle', { - defaultMessage: '{version} Upgrade Assistant', - values: { version: `${NEXT_MAJOR_VERSION}.0` }, - }), - order: 100, - url: `#${BASE_PATH}`, - }); - - app.mount( - {}, - { - __LEGACY: { - // While there is not an NP API for registering management section apps yet - renderToElement: RootComponent => { - uiModules - .get('kibana') - .directive('upgradeAssistant', (reactDirective: any) => { - return reactDirective(wrapInI18nContext(RootComponent)); - }); - }, - }, - } - ); - }, - }; - }, - }, - }, - }; - - const pluginInstance = plugin(); - - pluginInstance.setup(npSetup.core, legacyPluginsShim); -} - -startApp(); diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/app.tsx b/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/app.tsx deleted file mode 100644 index 571967ab114c9..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/app.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; - -import { EuiPageHeader, EuiPageHeaderSection, EuiTitle } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { NEXT_MAJOR_VERSION } from '../../../common/version'; -import { UpgradeAssistantTabs } from './components/tabs'; -import { AppContextProvider, ContextValue, AppContext } from './app_context'; - -type AppDependencies = ContextValue; - -export const RootComponent = (deps: AppDependencies) => { - return ( - -
- - - -

- -

-
-
-
- - {({ http }) => } - -
-
- ); -}; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/polling_service.test.mocks.ts b/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/polling_service.test.mocks.ts deleted file mode 100644 index dc7a758839fe5..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/polling_service.test.mocks.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { ReindexStatus, ReindexStep } from '../../../../../../../../common/types'; - -export const mockClient = { - post: jest.fn().mockResolvedValue({ - lastCompletedStep: ReindexStep.created, - status: ReindexStatus.inProgress, - }), - get: jest.fn().mockResolvedValue({ - status: 200, - data: { - warnings: [], - reindexOp: null, - }, - }), -}; -jest.mock('axios', () => ({ - create: jest.fn().mockReturnValue(mockClient), -})); diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/plugin.ts b/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/plugin.ts deleted file mode 100644 index ed85b988c25d6..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/plugin.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Plugin, CoreSetup } from 'src/core/public'; -import { RootComponent } from './application/app'; -import { LegacyPlugins } from '../legacy'; - -export class UpgradeAssistantUIPlugin implements Plugin { - async setup({ http }: CoreSetup, { cloud, management, __LEGACY: { XSRF } }: LegacyPlugins) { - const appRegistrar = management.sections.get('kibana'); - const isCloudEnabled = !!(cloud && cloud.isCloudEnabled); - - return appRegistrar.registerApp({ - mount(__, { __LEGACY: { renderToElement } }) { - return renderToElement(() => RootComponent({ http, XSRF, isCloudEnabled })); - }, - }); - } - async start() {} - async stop() {} -} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/index.ts b/x-pack/legacy/plugins/upgrade_assistant/server/index.ts deleted file mode 100644 index 8b0704283509d..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/server/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export { plugin } from './np_ready'; diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_open_apis.ts b/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_open_apis.ts deleted file mode 100644 index b52b3b812b7f9..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_open_apis.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - UIOpen, - UIOpenOption, - UPGRADE_ASSISTANT_DOC_ID, - UPGRADE_ASSISTANT_TYPE, -} from '../../../../common/types'; -import { RequestShim, ServerShim } from '../../types'; - -async function incrementUIOpenOptionCounter(server: ServerShim, uiOpenOptionCounter: UIOpenOption) { - const { getSavedObjectsRepository } = server.savedObjects; - const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('admin'); - const internalRepository = getSavedObjectsRepository(callWithInternalUser); - - await internalRepository.incrementCounter( - UPGRADE_ASSISTANT_TYPE, - UPGRADE_ASSISTANT_DOC_ID, - `ui_open.${uiOpenOptionCounter}` - ); -} - -export async function upsertUIOpenOption(server: ServerShim, req: RequestShim): Promise { - const { overview, cluster, indices } = req.payload as UIOpen; - - if (overview) { - await incrementUIOpenOptionCounter(server, 'overview'); - } - - if (cluster) { - await incrementUIOpenOptionCounter(server, 'cluster'); - } - - if (indices) { - await incrementUIOpenOptionCounter(server, 'indices'); - } - - return { - overview, - cluster, - indices, - }; -} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_reindex_apis.ts b/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_reindex_apis.ts deleted file mode 100644 index 626d51b298e72..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_reindex_apis.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - UIReindex, - UIReindexOption, - UPGRADE_ASSISTANT_DOC_ID, - UPGRADE_ASSISTANT_TYPE, -} from '../../../../common/types'; -import { RequestShim, ServerShim } from '../../types'; - -async function incrementUIReindexOptionCounter( - server: ServerShim, - uiOpenOptionCounter: UIReindexOption -) { - const { getSavedObjectsRepository } = server.savedObjects; - const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('admin'); - const internalRepository = getSavedObjectsRepository(callWithInternalUser); - - await internalRepository.incrementCounter( - UPGRADE_ASSISTANT_TYPE, - UPGRADE_ASSISTANT_DOC_ID, - `ui_reindex.${uiOpenOptionCounter}` - ); -} - -export async function upsertUIReindexOption( - server: ServerShim, - req: RequestShim -): Promise { - const { close, open, start, stop } = req.payload as UIReindex; - - if (close) { - await incrementUIReindexOptionCounter(server, 'close'); - } - - if (open) { - await incrementUIReindexOptionCounter(server, 'open'); - } - - if (start) { - await incrementUIReindexOptionCounter(server, 'start'); - } - - if (stop) { - await incrementUIReindexOptionCounter(server, 'stop'); - } - - return { - close, - open, - start, - stop, - }; -} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/plugin.ts b/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/plugin.ts deleted file mode 100644 index fae369fa59394..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/plugin.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { Plugin, CoreSetup, CoreStart } from 'src/core/server'; -import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { ServerShim, ServerShimWithRouter } from './types'; -import { credentialStoreFactory } from './lib/reindexing/credential_store'; -import { registerUpgradeAssistantUsageCollector } from './lib/telemetry'; -import { registerClusterCheckupRoutes } from './routes/cluster_checkup'; -import { registerDeprecationLoggingRoutes } from './routes/deprecation_logging'; -import { registerReindexIndicesRoutes, registerReindexWorker } from './routes/reindex_indices'; -import { CloudSetup } from '../../../../../plugins/cloud/server'; -import { registerTelemetryRoutes } from './routes/telemetry'; - -interface PluginsSetup { - __LEGACY: ServerShim; - usageCollection: UsageCollectionSetup; - cloud?: CloudSetup; -} - -export class UpgradeAssistantServerPlugin implements Plugin { - setup({ http }: CoreSetup, { __LEGACY, usageCollection, cloud }: PluginsSetup) { - const router = http.createRouter(); - const shimWithRouter: ServerShimWithRouter = { ...__LEGACY, router }; - registerClusterCheckupRoutes(shimWithRouter, { cloud }); - registerDeprecationLoggingRoutes(shimWithRouter); - - // The ReindexWorker uses a map of request headers that contain the authentication credentials - // for a given reindex. We cannot currently store these in an the .kibana index b/c we do not - // want to expose these credentials to any unauthenticated users. We also want to avoid any need - // to add a user for a special index just for upgrading. This in-memory cache allows us to - // process jobs without the browser staying on the page, but will require that jobs go into - // a paused state if no Kibana nodes have the required credentials. - const credentialStore = credentialStoreFactory(); - - const worker = registerReindexWorker(__LEGACY, credentialStore); - registerReindexIndicesRoutes(shimWithRouter, worker, credentialStore); - - // Bootstrap the needed routes and the collector for the telemetry - registerTelemetryRoutes(shimWithRouter); - registerUpgradeAssistantUsageCollector(usageCollection, __LEGACY); - } - - start(core: CoreStart, plugins: any) {} - - stop(): void {} -} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/cluster_checkup.ts b/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/cluster_checkup.ts deleted file mode 100644 index 81cf690d813ad..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/cluster_checkup.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import _ from 'lodash'; -import { ServerShimWithRouter } from '../types'; -import { getUpgradeAssistantStatus } from '../lib/es_migration_apis'; -import { versionCheckHandlerWrapper } from '../lib/es_version_precheck'; -import { CloudSetup } from '../../../../../../plugins/cloud/server'; -import { createRequestShim } from './create_request_shim'; - -interface PluginsSetup { - cloud?: CloudSetup; -} - -export function registerClusterCheckupRoutes( - server: ServerShimWithRouter, - pluginsSetup: PluginsSetup -) { - const { cloud } = pluginsSetup; - const isCloudEnabled = !!(cloud && cloud.isCloudEnabled); - const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); - - server.router.get( - { - path: '/api/upgrade_assistant/status', - validate: false, - }, - versionCheckHandlerWrapper(async (ctx, request, response) => { - const reqShim = createRequestShim(request); - try { - return response.ok({ - body: await getUpgradeAssistantStatus(callWithRequest, reqShim, isCloudEnabled), - }); - } catch (e) { - if (e.status === 403) { - return response.forbidden(e.message); - } - - return response.internalError({ body: e }); - } - }) - ); -} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/create_request_shim.ts b/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/create_request_shim.ts deleted file mode 100644 index b1a5c8b72d0e0..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/create_request_shim.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { KibanaRequest } from 'kibana/server'; -import { RequestShim } from '../types'; - -export const createRequestShim = (req: KibanaRequest): RequestShim => { - return { - headers: req.headers as Record, - payload: req.body || (req as any).payload, - params: req.params, - }; -}; diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/deprecation_logging.ts b/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/deprecation_logging.ts deleted file mode 100644 index 7e19ef3fb6047..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/deprecation_logging.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { schema } from '@kbn/config-schema'; - -import { - getDeprecationLoggingStatus, - setDeprecationLogging, -} from '../lib/es_deprecation_logging_apis'; -import { versionCheckHandlerWrapper } from '../lib/es_version_precheck'; -import { ServerShimWithRouter } from '../types'; -import { createRequestShim } from './create_request_shim'; - -export function registerDeprecationLoggingRoutes(server: ServerShimWithRouter) { - const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); - - server.router.get( - { - path: '/api/upgrade_assistant/deprecation_logging', - validate: false, - }, - versionCheckHandlerWrapper(async (ctx, request, response) => { - const reqShim = createRequestShim(request); - try { - const result = await getDeprecationLoggingStatus(callWithRequest, reqShim); - return response.ok({ body: result }); - } catch (e) { - return response.internalError({ body: e }); - } - }) - ); - - server.router.put( - { - path: '/api/upgrade_assistant/deprecation_logging', - validate: { - body: schema.object({ - isEnabled: schema.boolean(), - }), - }, - }, - versionCheckHandlerWrapper(async (ctx, request, response) => { - const reqShim = createRequestShim(request); - try { - const { isEnabled } = reqShim.payload as { isEnabled: boolean }; - return response.ok({ - body: await setDeprecationLogging(callWithRequest, reqShim, isEnabled), - }); - } catch (e) { - return response.internalError({ body: e }); - } - }) - ); -} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/reindex_indices.ts b/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/reindex_indices.ts deleted file mode 100644 index c22f12316bd02..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/reindex_indices.ts +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { schema } from '@kbn/config-schema'; -import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; -import { SavedObjectsClientContract } from 'kibana/server'; -import { ReindexStatus } from '../../../common/types'; -import { versionCheckHandlerWrapper } from '../lib/es_version_precheck'; -import { reindexServiceFactory, ReindexWorker } from '../lib/reindexing'; -import { CredentialStore } from '../lib/reindexing/credential_store'; -import { reindexActionsFactory } from '../lib/reindexing/reindex_actions'; -import { ServerShim, ServerShimWithRouter } from '../types'; -import { createRequestShim } from './create_request_shim'; - -export function registerReindexWorker(server: ServerShim, credentialStore: CredentialStore) { - const { callWithRequest, callWithInternalUser } = server.plugins.elasticsearch.getCluster( - 'admin' - ); - const xpackInfo = server.plugins.xpack_main.info; - const savedObjectsRepository = server.savedObjects.getSavedObjectsRepository( - callWithInternalUser - ); - const savedObjectsClient = new server.savedObjects.SavedObjectsClient( - savedObjectsRepository - ) as SavedObjectsClientContract; - - // Cannot pass server.log directly because it's value changes during startup (?). - // Use this function to proxy through. - const log = (tags: string | string[], data?: string | object | (() => any), timestamp?: number) => - server.log(tags, data, timestamp); - - const worker = new ReindexWorker( - savedObjectsClient, - credentialStore, - callWithRequest, - callWithInternalUser, - xpackInfo, - log - ); - - // Wait for ES connection before starting the polling loop. - server.plugins.elasticsearch.waitUntilReady().then(() => { - worker.start(); - server.events.on('stop', () => worker.stop()); - }); - - return worker; -} - -export function registerReindexIndicesRoutes( - server: ServerShimWithRouter, - worker: ReindexWorker, - credentialStore: CredentialStore -) { - const { callWithRequest } = server.plugins.elasticsearch.getCluster('admin'); - const xpackInfo = server.plugins.xpack_main.info; - const BASE_PATH = '/api/upgrade_assistant/reindex'; - - // Start reindex for an index - server.router.post( - { - path: `${BASE_PATH}/{indexName}`, - validate: { - params: schema.object({ - indexName: schema.string(), - }), - }, - }, - versionCheckHandlerWrapper(async (ctx, request, response) => { - const reqShim = createRequestShim(request); - const { indexName } = reqShim.params; - const { client } = ctx.core.savedObjects; - const callCluster = callWithRequest.bind(null, reqShim) as CallCluster; - const reindexActions = reindexActionsFactory(client, callCluster); - const reindexService = reindexServiceFactory( - callCluster, - xpackInfo, - reindexActions, - server.log - ); - - try { - if (!(await reindexService.hasRequiredPrivileges(indexName))) { - return response.forbidden({ - body: `You do not have adequate privileges to reindex this index.`, - }); - } - - const existingOp = await reindexService.findReindexOperation(indexName); - - // If the reindexOp already exists and it's paused, resume it. Otherwise create a new one. - const reindexOp = - existingOp && existingOp.attributes.status === ReindexStatus.paused - ? await reindexService.resumeReindexOperation(indexName) - : await reindexService.createReindexOperation(indexName); - - // Add users credentials for the worker to use - credentialStore.set(reindexOp, reqShim.headers); - - // Kick the worker on this node to immediately pickup the new reindex operation. - worker.forceRefresh(); - - return response.ok({ body: reindexOp.attributes }); - } catch (e) { - return response.internalError({ body: e }); - } - }) - ); - - // Get status - server.router.get( - { - path: `${BASE_PATH}/{indexName}`, - validate: { - params: schema.object({ - indexName: schema.string(), - }), - }, - }, - versionCheckHandlerWrapper(async (ctx, request, response) => { - const reqShim = createRequestShim(request); - const { client } = ctx.core.savedObjects; - const { indexName } = reqShim.params; - const callCluster = callWithRequest.bind(null, reqShim) as CallCluster; - const reindexActions = reindexActionsFactory(client, callCluster); - const reindexService = reindexServiceFactory( - callCluster, - xpackInfo, - reindexActions, - server.log - ); - - try { - const hasRequiredPrivileges = await reindexService.hasRequiredPrivileges(indexName); - const reindexOp = await reindexService.findReindexOperation(indexName); - // If the user doesn't have privileges than querying for warnings is going to fail. - const warnings = hasRequiredPrivileges - ? await reindexService.detectReindexWarnings(indexName) - : []; - const indexGroup = reindexService.getIndexGroup(indexName); - - return response.ok({ - body: { - reindexOp: reindexOp ? reindexOp.attributes : null, - warnings, - indexGroup, - hasRequiredPrivileges, - }, - }); - } catch (e) { - if (!e.isBoom) { - return response.internalError({ body: e }); - } - return response.customError({ - body: { - message: e.message, - }, - statusCode: e.statusCode, - }); - } - }) - ); - - // Cancel reindex - server.router.post( - { - path: `${BASE_PATH}/{indexName}/cancel`, - validate: { - params: schema.object({ - indexName: schema.string(), - }), - }, - }, - versionCheckHandlerWrapper(async (ctx, request, response) => { - const reqShim = createRequestShim(request); - const { indexName } = reqShim.params; - const { client } = ctx.core.savedObjects; - const callCluster = callWithRequest.bind(null, reqShim) as CallCluster; - const reindexActions = reindexActionsFactory(client, callCluster); - const reindexService = reindexServiceFactory( - callCluster, - xpackInfo, - reindexActions, - server.log - ); - - try { - await reindexService.cancelReindexing(indexName); - - return response.ok({ body: { acknowledged: true } }); - } catch (e) { - if (!e.isBoom) { - return response.internalError({ body: e }); - } - return response.customError({ - body: { - message: e.message, - }, - statusCode: e.statusCode, - }); - } - }) - ); -} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/types.ts b/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/types.ts deleted file mode 100644 index 77ba97529c32f..0000000000000 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/types.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { Legacy } from 'kibana'; -import { IRouter } from 'src/core/server'; -import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; -import { XPackMainPlugin } from '../../../xpack_main/server/xpack_main'; - -export interface ServerShim { - plugins: { - elasticsearch: ElasticsearchPlugin; - xpack_main: XPackMainPlugin; - }; - log: any; - events: any; - savedObjects: Legacy.SavedObjectsService; -} - -export interface ServerShimWithRouter extends ServerShim { - router: IRouter; -} - -export interface RequestShim { - headers: Record; - payload: any; - params: any; -} diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/index.ts b/x-pack/plugins/upgrade_assistant/common/config.ts similarity index 54% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/index.ts rename to x-pack/plugins/upgrade_assistant/common/config.ts index 020d6972f8280..8a13aedd5fdd8 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/index.ts +++ b/x-pack/plugins/upgrade_assistant/common/config.ts @@ -4,8 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { UpgradeAssistantUIPlugin } from './plugin'; +import { schema, TypeOf } from '@kbn/config-schema'; -export const plugin = () => { - return new UpgradeAssistantUIPlugin(); -}; +export const configSchema = schema.object({ + enabled: schema.boolean({ defaultValue: true }), +}); + +export type Config = TypeOf; diff --git a/x-pack/legacy/plugins/upgrade_assistant/common/types.ts b/x-pack/plugins/upgrade_assistant/common/types.ts similarity index 88% rename from x-pack/legacy/plugins/upgrade_assistant/common/types.ts rename to x-pack/plugins/upgrade_assistant/common/types.ts index 0e65506bb584d..a0c12154988a1 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/common/types.ts +++ b/x-pack/plugins/upgrade_assistant/common/types.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { DeprecationInfo } from 'src/legacy/core_plugins/elasticsearch'; import { SavedObject, SavedObjectAttributes } from 'src/core/public'; export enum ReindexStep { @@ -114,3 +115,15 @@ export interface UpgradeAssistantTelemetry { export interface UpgradeAssistantTelemetrySavedObjectAttributes { [key: string]: any; } + +export interface EnrichedDeprecationInfo extends DeprecationInfo { + index?: string; + node?: string; + reindex?: boolean; +} + +export interface UpgradeAssistantStatus { + readyForUpgrade: boolean; + cluster: EnrichedDeprecationInfo[]; + indices: EnrichedDeprecationInfo[]; +} diff --git a/x-pack/legacy/plugins/upgrade_assistant/common/version.ts b/x-pack/plugins/upgrade_assistant/common/version.ts similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/common/version.ts rename to x-pack/plugins/upgrade_assistant/common/version.ts diff --git a/x-pack/plugins/upgrade_assistant/kibana.json b/x-pack/plugins/upgrade_assistant/kibana.json new file mode 100644 index 0000000000000..273036a653aeb --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/kibana.json @@ -0,0 +1,9 @@ +{ + "id": "upgradeAssistant", + "version": "kibana", + "server": true, + "ui": true, + "configPath": ["xpack", "upgrade_assistant"], + "requiredPlugins": ["management", "licensing"], + "optionalPlugins": ["cloud", "usageCollection"] +} diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/index.scss b/x-pack/plugins/upgrade_assistant/public/application/_index.scss similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/index.scss rename to x-pack/plugins/upgrade_assistant/public/application/_index.scss diff --git a/x-pack/plugins/upgrade_assistant/public/application/app.tsx b/x-pack/plugins/upgrade_assistant/public/application/app.tsx new file mode 100644 index 0000000000000..17eff71f1039b --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/app.tsx @@ -0,0 +1,44 @@ +/* + * 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 { I18nStart } from 'src/core/public'; +import { EuiPageHeader, EuiPageHeaderSection, EuiTitle } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { NEXT_MAJOR_VERSION } from '../../common/version'; +import { UpgradeAssistantTabs } from './components/tabs'; +import { AppContextProvider, ContextValue, AppContext } from './app_context'; + +export interface AppDependencies extends ContextValue { + i18n: I18nStart; +} + +export const RootComponent = ({ i18n, ...contexValue }: AppDependencies) => { + return ( + + +
+ + + +

+ +

+
+
+
+ + {({ http }) => } + +
+
+
+ ); +}; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/app_context.tsx b/x-pack/plugins/upgrade_assistant/public/application/app_context.tsx similarity index 98% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/app_context.tsx rename to x-pack/plugins/upgrade_assistant/public/application/app_context.tsx index a48a4efa3bbdf..1ae9dabd69481 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/app_context.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/app_context.tsx @@ -9,7 +9,6 @@ import React, { createContext, useContext } from 'react'; export interface ContextValue { http: HttpSetup; isCloudEnabled: boolean; - XSRF: string; } export const AppContext = createContext({} as any); diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/_index.scss similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/_index.scss diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/error_banner.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/error_banner.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/error_banner.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/error_banner.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/latest_minor_banner.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/latest_minor_banner.tsx similarity index 98% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/latest_minor_banner.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/latest_minor_banner.tsx index 864df292fbffe..43d0364425cbb 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/latest_minor_banner.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/latest_minor_banner.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { EuiCallOut, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { CURRENT_MAJOR_VERSION, NEXT_MAJOR_VERSION } from '../../../../common/version'; +import { CURRENT_MAJOR_VERSION, NEXT_MAJOR_VERSION } from '../../../common/version'; export const LatestMinorBanner: React.FunctionComponent = () => ( ({ - get: jest.fn(), - create: jest.fn(), -})); - +import { httpServiceMock } from 'src/core/public/mocks'; import { UpgradeAssistantTabs } from './tabs'; import { LoadingState } from './types'; -import axios from 'axios'; import { OverviewTab } from './tabs/overview'; // Used to wait for promises to resolve and renders to finish before reading updates const promisesToResolve = () => new Promise(resolve => setTimeout(resolve, 0)); -const mockHttp = { - basePath: { - prepend: () => 'test', - }, - fetch() {}, -}; +const mockHttp = httpServiceMock.createSetupContract(); describe('UpgradeAssistantTabs', () => { test('renders loading state', async () => { - // @ts-ignore - axios.get.mockReturnValue( + mockHttp.get.mockReturnValue( new Promise(resolve => { /* never resolve */ }) ); - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl(); // Should pass down loading status to child component expect(wrapper.find(OverviewTab).prop('loadingState')).toEqual(LoadingState.Loading); }); test('successful data fetch', async () => { // @ts-ignore - axios.get.mockResolvedValue({ + mockHttp.get.mockResolvedValue({ data: { cluster: [], indices: [], }, }); const wrapper = mountWithIntl(); - expect(axios.get).toHaveBeenCalled(); + expect(mockHttp.get).toHaveBeenCalled(); await promisesToResolve(); wrapper.update(); // Should pass down success status to child component @@ -59,7 +47,7 @@ describe('UpgradeAssistantTabs', () => { test('network failure', async () => { // @ts-ignore - axios.get.mockRejectedValue(new Error(`oh no!`)); + mockHttp.get.mockRejectedValue(new Error(`oh no!`)); const wrapper = mountWithIntl(); await promisesToResolve(); wrapper.update(); @@ -69,7 +57,7 @@ describe('UpgradeAssistantTabs', () => { it('upgrade error', async () => { // @ts-ignore - axios.get.mockRejectedValue({ response: { status: 426 } }); + mockHttp.get.mockRejectedValue({ response: { status: 426 } }); const wrapper = mountWithIntl(); await promisesToResolve(); wrapper.update(); diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs.tsx similarity index 96% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs.tsx index 0b154fb20404d..43ec5554aaaee 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import axios from 'axios'; import { findIndex, get, set } from 'lodash'; import React from 'react'; @@ -18,7 +17,7 @@ import { import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; import { HttpSetup } from 'src/core/public'; -import { UpgradeAssistantStatus } from '../../../../server/np_ready/lib/es_migration_apis'; +import { UpgradeAssistantStatus } from '../../../common/types'; import { LatestMinorBanner } from './latest_minor_banner'; import { CheckupTab } from './tabs/checkup'; import { OverviewTab } from './tabs/overview'; @@ -153,12 +152,10 @@ export class UpgradeAssistantTabsUI extends React.Component { private loadData = async () => { try { this.setState({ loadingState: LoadingState.Loading }); - const resp = await axios.get( - this.props.http.basePath.prepend('/api/upgrade_assistant/status') - ); + const resp = await this.props.http.get('/api/upgrade_assistant/status'); this.setState({ loadingState: LoadingState.Success, - checkupData: resp.data, + checkupData: resp, }); } catch (e) { if (get(e, 'response.status') === 426) { diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/__fixtures__/checkup_api_response.json b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/__fixtures__/checkup_api_response.json similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/__fixtures__/checkup_api_response.json rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/__fixtures__/checkup_api_response.json diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/__snapshots__/checkup_tab.test.tsx.snap b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/__snapshots__/checkup_tab.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/__snapshots__/checkup_tab.test.tsx.snap rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/__snapshots__/checkup_tab.test.tsx.snap diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/__snapshots__/filter_bar.test.tsx.snap b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/__snapshots__/filter_bar.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/__snapshots__/filter_bar.test.tsx.snap rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/__snapshots__/filter_bar.test.tsx.snap diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/__snapshots__/group_by_bar.test.tsx.snap b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/__snapshots__/group_by_bar.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/__snapshots__/group_by_bar.test.tsx.snap rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/__snapshots__/group_by_bar.test.tsx.snap diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/_index.scss similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/_index.scss diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/checkup_tab.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/checkup_tab.test.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/checkup_tab.test.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/checkup_tab.test.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/checkup_tab.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/checkup_tab.tsx similarity index 99% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/checkup_tab.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/checkup_tab.tsx index 7e862a846290b..b047427174e08 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/checkup_tab.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/checkup_tab.tsx @@ -18,7 +18,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { NEXT_MAJOR_VERSION } from '../../../../../../common/version'; +import { NEXT_MAJOR_VERSION } from '../../../../../common/version'; import { LoadingErrorBanner } from '../../error_banner'; import { GroupByOption, diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/constants.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/constants.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/constants.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/constants.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/controls.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/controls.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/controls.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/controls.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/_cell.scss b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/_cell.scss similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/_cell.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/_cell.scss diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/_deprecations.scss b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/_deprecations.scss similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/_deprecations.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/_deprecations.scss diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/_index.scss similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/_index.scss diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/cell.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/cell.tsx similarity index 94% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/cell.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/cell.tsx index 4bd2f7c4bf62c..879bb695ca60a 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/cell.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/cell.tsx @@ -79,9 +79,7 @@ export const DeprecationCell: FunctionComponent = ({ {reindexIndexName && ( - {({ http, XSRF }) => ( - - )} + {({ http }) => } )} diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/count_summary.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/count_summary.tsx similarity index 93% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/count_summary.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/count_summary.tsx index a0e55dc55c865..7e5172a361a56 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/count_summary.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/count_summary.tsx @@ -8,7 +8,7 @@ import React, { Fragment, FunctionComponent } from 'react'; import { EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EnrichedDeprecationInfo } from '../../../../../../../server/np_ready/lib/es_migration_apis'; +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; export const DeprecationCountSummary: FunctionComponent<{ deprecations: EnrichedDeprecationInfo[]; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/grouped.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/grouped.test.tsx similarity index 98% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/grouped.test.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/grouped.test.tsx index 28f5f6894b78f..c6309fb57d786 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/grouped.test.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/grouped.test.tsx @@ -11,7 +11,7 @@ import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; import { EuiBadge, EuiPagination } from '@elastic/eui'; import { DeprecationInfo } from 'src/legacy/core_plugins/elasticsearch'; -import { EnrichedDeprecationInfo } from '../../../../../../../server/np_ready/lib/es_migration_apis'; +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; import { GroupByOption, LevelFilterOption } from '../../../types'; import { DeprecationAccordion, filterDeps, GroupedDeprecations } from './grouped'; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/grouped.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/grouped.tsx similarity index 98% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/grouped.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/grouped.tsx index 74f66b6c4fb35..8fa78639c39d3 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/grouped.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/grouped.tsx @@ -19,7 +19,7 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; import { DeprecationInfo } from 'src/legacy/core_plugins/elasticsearch'; -import { EnrichedDeprecationInfo } from '../../../../../../../server/np_ready/lib/es_migration_apis'; +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; import { GroupByOption, LevelFilterOption } from '../../../types'; import { DeprecationCountSummary } from './count_summary'; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/health.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/health.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/health.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/health.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/index.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/index.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/index.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/index.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/index_table.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/index_table.test.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/index_table.test.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/index_table.test.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/index_table.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/index_table.tsx similarity index 96% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/index_table.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/index_table.tsx index 835affce59070..5506528a3ded0 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/index_table.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/index_table.tsx @@ -148,9 +148,7 @@ export class IndexDeprecationTableUI extends React.Component< render(indexDep: IndexDeprecationDetails) { return ( - {({ XSRF, http }) => ( - - )} + {({ http }) => } ); }, diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/list.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/list.test.tsx similarity index 96% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/list.test.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/list.test.tsx index 78ded73593464..a1e173737bab0 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/list.test.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/list.test.tsx @@ -7,7 +7,7 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { EnrichedDeprecationInfo } from '../../../../../../../server/np_ready/lib/es_migration_apis'; +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; import { GroupByOption } from '../../../types'; import { DeprecationList } from './list'; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/list.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/list.tsx similarity index 97% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/list.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/list.tsx index 15a3d94974dcd..a46bc0d12fad4 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/list.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/list.tsx @@ -7,7 +7,7 @@ import React, { FunctionComponent } from 'react'; import { DeprecationInfo } from 'src/legacy/core_plugins/elasticsearch'; -import { EnrichedDeprecationInfo } from '../../../../../../../server/np_ready/lib/es_migration_apis'; +import { EnrichedDeprecationInfo } from '../../../../../../common/types'; import { GroupByOption } from '../../../types'; import { COLOR_MAP, LEVEL_MAP } from '../constants'; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/_button.scss b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/_button.scss similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/_button.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/_button.scss diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/_index.scss similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/_index.scss diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/button.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/button.tsx similarity index 97% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/button.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/button.tsx index 2a28018a3ae81..30b46e0c15213 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/button.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/button.tsx @@ -11,14 +11,13 @@ import { Subscription } from 'rxjs'; import { EuiButton, EuiLoadingSpinner } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { HttpSetup } from 'src/core/public'; -import { ReindexStatus, UIReindexOption } from '../../../../../../../../common/types'; +import { ReindexStatus, UIReindexOption } from '../../../../../../../common/types'; import { LoadingState } from '../../../../types'; import { ReindexFlyout } from './flyout'; import { ReindexPollingService, ReindexState } from './polling_service'; interface ReindexButtonProps { indexName: string; - xsrf: string; http: HttpSetup; } @@ -154,8 +153,8 @@ export class ReindexButton extends React.Component { diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/flyout/warnings_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/flyout/warnings_step.tsx similarity index 99% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/flyout/warnings_step.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/flyout/warnings_step.tsx index 91e35c0bd7dc0..643dd2e9b6efc 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/flyout/warnings_step.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/flyout/warnings_step.tsx @@ -21,7 +21,7 @@ import { EuiText, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ReindexWarning } from '../../../../../../../../../common/types'; +import { ReindexWarning } from '../../../../../../../../common/types'; interface CheckedIds { [id: string]: boolean; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/index.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/index.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/index.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/index.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/polling_service.test.ts b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/polling_service.test.ts similarity index 63% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/polling_service.test.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/polling_service.test.ts index cb2a0856f0f2e..4228426d62159 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/polling_service.test.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/polling_service.test.ts @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mockClient } from './polling_service.test.mocks'; - -import { ReindexStatus, ReindexStep } from '../../../../../../../../common/types'; +import { ReindexStatus, ReindexStep } from '../../../../../../../common/types'; import { ReindexPollingService } from './polling_service'; import { httpServiceMock } from 'src/core/public/http/http_service.mock'; +const mockClient = httpServiceMock.createSetupContract(); + describe('ReindexPollingService', () => { beforeEach(() => { mockClient.post.mockReset(); @@ -18,18 +18,11 @@ describe('ReindexPollingService', () => { it('does not poll when reindexOp is null', async () => { mockClient.get.mockResolvedValueOnce({ - status: 200, - data: { - warnings: [], - reindexOp: null, - }, + warnings: [], + reindexOp: null, }); - const service = new ReindexPollingService( - 'myIndex', - 'myXsrf', - httpServiceMock.createSetupContract() - ); + const service = new ReindexPollingService('myIndex', mockClient); service.updateStatus(); await new Promise(resolve => setTimeout(resolve, 1200)); // wait for poll interval @@ -39,22 +32,15 @@ describe('ReindexPollingService', () => { it('does not poll when first check is a 200 and status is failed', async () => { mockClient.get.mockResolvedValue({ - status: 200, - data: { - warnings: [], - reindexOp: { - lastCompletedStep: ReindexStep.created, - status: ReindexStatus.failed, - errorMessage: `Oh no!`, - }, + warnings: [], + reindexOp: { + lastCompletedStep: ReindexStep.created, + status: ReindexStatus.failed, + errorMessage: `Oh no!`, }, }); - const service = new ReindexPollingService( - 'myIndex', - 'myXsrf', - httpServiceMock.createSetupContract() - ); + const service = new ReindexPollingService('myIndex', mockClient); service.updateStatus(); await new Promise(resolve => setTimeout(resolve, 1200)); // wait for poll interval @@ -65,21 +51,14 @@ describe('ReindexPollingService', () => { it('begins to poll when first check is a 200 and status is inProgress', async () => { mockClient.get.mockResolvedValue({ - status: 200, - data: { - warnings: [], - reindexOp: { - lastCompletedStep: ReindexStep.created, - status: ReindexStatus.inProgress, - }, + warnings: [], + reindexOp: { + lastCompletedStep: ReindexStep.created, + status: ReindexStatus.inProgress, }, }); - const service = new ReindexPollingService( - 'myIndex', - 'myXsrf', - httpServiceMock.createSetupContract() - ); + const service = new ReindexPollingService('myIndex', mockClient); service.updateStatus(); await new Promise(resolve => setTimeout(resolve, 1200)); // wait for poll interval @@ -89,11 +68,7 @@ describe('ReindexPollingService', () => { describe('startReindex', () => { it('posts to endpoint', async () => { - const service = new ReindexPollingService( - 'myIndex', - 'myXsrf', - httpServiceMock.createSetupContract() - ); + const service = new ReindexPollingService('myIndex', mockClient); await service.startReindex(); expect(mockClient.post).toHaveBeenCalledWith('/api/upgrade_assistant/reindex/myIndex'); @@ -102,11 +77,7 @@ describe('ReindexPollingService', () => { describe('cancelReindex', () => { it('posts to cancel endpoint', async () => { - const service = new ReindexPollingService( - 'myIndex', - 'myXsrf', - httpServiceMock.createSetupContract() - ); + const service = new ReindexPollingService('myIndex', mockClient); await service.cancelReindex(); expect(mockClient.post).toHaveBeenCalledWith('/api/upgrade_assistant/reindex/myIndex/cancel'); diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/polling_service.ts b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/polling_service.ts similarity index 82% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/polling_service.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/polling_service.ts index 879fafe610982..6fe6a85905706 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/deprecations/reindex/polling_service.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/deprecations/reindex/polling_service.ts @@ -3,8 +3,6 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import axios, { AxiosInstance } from 'axios'; - import { BehaviorSubject } from 'rxjs'; import { HttpSetup } from 'src/core/public'; @@ -14,7 +12,7 @@ import { ReindexStatus, ReindexStep, ReindexWarning, -} from '../../../../../../../../common/types'; +} from '../../../../../../../common/types'; import { LoadingState } from '../../../../types'; const POLL_INTERVAL = 1000; @@ -45,24 +43,13 @@ interface StatusResponse { export class ReindexPollingService { public status$: BehaviorSubject; private pollTimeout?: NodeJS.Timeout; - private APIClient: AxiosInstance; - constructor(private indexName: string, private xsrf: string, private http: HttpSetup) { + constructor(private indexName: string, private http: HttpSetup) { this.status$ = new BehaviorSubject({ loadingState: LoadingState.Loading, errorMessage: null, reindexTaskPercComplete: null, }); - - this.APIClient = axios.create({ - headers: { - Accept: 'application/json', - credentials: 'same-origin', - 'Content-Type': 'application/json', - 'kbn-version': this.xsrf, - 'kbn-xsrf': this.xsrf, - }, - }); } public updateStatus = async () => { @@ -70,8 +57,8 @@ export class ReindexPollingService { this.stopPolling(); try { - const { data } = await this.APIClient.get( - this.http.basePath.prepend(`/api/upgrade_assistant/reindex/${this.indexName}`) + const data = await this.http.get( + `/api/upgrade_assistant/reindex/${this.indexName}` ); this.updateWithResponse(data); @@ -107,8 +94,8 @@ export class ReindexPollingService { errorMessage: null, cancelLoadingState: undefined, }); - const { data } = await this.APIClient.post( - this.http.basePath.prepend(`/api/upgrade_assistant/reindex/${this.indexName}`) + const data = await this.http.post( + `/api/upgrade_assistant/reindex/${this.indexName}` ); this.updateWithResponse({ reindexOp: data }); @@ -125,9 +112,7 @@ export class ReindexPollingService { cancelLoadingState: LoadingState.Loading, }); - await this.APIClient.post( - this.http.basePath.prepend(`/api/upgrade_assistant/reindex/${this.indexName}/cancel`) - ); + await this.http.post(`/api/upgrade_assistant/reindex/${this.indexName}/cancel`); } catch (e) { this.status$.next({ ...this.status$.value, diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/filter_bar.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/filter_bar.test.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/filter_bar.test.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/filter_bar.test.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/filter_bar.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/filter_bar.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/filter_bar.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/filter_bar.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/group_by_bar.test.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/group_by_bar.test.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/group_by_bar.test.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/group_by_bar.test.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/group_by_bar.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/group_by_bar.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/group_by_bar.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/group_by_bar.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/index.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/index.tsx similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/checkup/index.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/checkup/index.tsx diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/_index.scss b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/_index.scss similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/_index.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/_index.scss diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/_steps.scss b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/_steps.scss similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/_steps.scss rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/_steps.scss diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/deprecation_logging_toggle.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/deprecation_logging_toggle.tsx similarity index 86% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/deprecation_logging_toggle.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/deprecation_logging_toggle.tsx index db37bc58904ec..0e6c79dc47b53 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/deprecation_logging_toggle.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/deprecation_logging_toggle.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import axios from 'axios'; import React from 'react'; import { EuiLoadingSpinner, EuiSwitch } from '@elastic/eui'; @@ -15,7 +14,6 @@ import { HttpSetup } from 'src/core/public'; import { LoadingState } from '../../types'; interface DeprecationLoggingTabProps extends ReactIntl.InjectedIntlProps { - xsrf: string; http: HttpSetup; } @@ -88,12 +86,10 @@ export class DeprecationLoggingToggleUI extends React.Component< private loadData = async () => { try { this.setState({ loadingState: LoadingState.Loading }); - const resp = await axios.get( - this.props.http.basePath.prepend('/api/upgrade_assistant/deprecation_logging') - ); + const resp = await this.props.http.get('/api/upgrade_assistant/deprecation_logging'); this.setState({ loadingState: LoadingState.Success, - loggingEnabled: resp.data.isEnabled, + loggingEnabled: resp.isEnabled, }); } catch (e) { this.setState({ loadingState: LoadingState.Error }); @@ -102,26 +98,19 @@ export class DeprecationLoggingToggleUI extends React.Component< private toggleLogging = async () => { try { - const { http, xsrf } = this.props; // Optimistically toggle the UI const newEnabled = !this.state.loggingEnabled; this.setState({ loadingState: LoadingState.Loading, loggingEnabled: newEnabled }); - const resp = await axios.put( - http.basePath.prepend('/api/upgrade_assistant/deprecation_logging'), - { + const resp = await this.props.http.put('/api/upgrade_assistant/deprecation_logging', { + body: JSON.stringify({ isEnabled: newEnabled, - }, - { - headers: { - 'kbn-xsrf': xsrf, - }, - } - ); + }), + }); this.setState({ loadingState: LoadingState.Success, - loggingEnabled: resp.data.isEnabled, + loggingEnabled: resp.isEnabled, }); } catch (e) { this.setState({ loadingState: LoadingState.Error }); diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/index.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/index.tsx similarity index 96% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/index.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/index.tsx index 284265bb31f14..aede377fa8d45 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/index.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/index.tsx @@ -17,7 +17,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { NEXT_MAJOR_VERSION } from '../../../../../../common/version'; +import { NEXT_MAJOR_VERSION } from '../../../../../common/version'; import { LoadingErrorBanner } from '../../error_banner'; import { LoadingState, UpgradeAssistantTabProps } from '../../types'; import { Steps } from './steps'; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/steps.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/steps.tsx similarity index 98% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/steps.tsx rename to x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/steps.tsx index ccba51c73c136..85d275b080e13 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/tabs/overview/steps.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/tabs/overview/steps.tsx @@ -19,7 +19,7 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; -import { CURRENT_MAJOR_VERSION, NEXT_MAJOR_VERSION } from '../../../../../../common/version'; +import { CURRENT_MAJOR_VERSION, NEXT_MAJOR_VERSION } from '../../../../../common/version'; import { UpgradeAssistantTabProps } from '../../types'; import { DeprecationLoggingToggle } from './deprecation_logging_toggle'; import { useAppContext } from '../../../app_context'; @@ -104,7 +104,7 @@ export const StepsUI: FunctionComponent - + ), diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/types.ts b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts similarity index 89% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/types.ts rename to x-pack/plugins/upgrade_assistant/public/application/components/types.ts index 2d9a373f20b7e..86d1486543596 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/components/types.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/types.ts @@ -6,10 +6,7 @@ import React from 'react'; -import { - EnrichedDeprecationInfo, - UpgradeAssistantStatus, -} from '../../../../server/np_ready/lib/es_migration_apis'; +import { EnrichedDeprecationInfo, UpgradeAssistantStatus } from '../../../common/types'; export interface UpgradeAssistantTabProps { alertBanner?: React.ReactNode; diff --git a/x-pack/plugins/upgrade_assistant/public/application/render_app.tsx b/x-pack/plugins/upgrade_assistant/public/application/render_app.tsx new file mode 100644 index 0000000000000..97120cfc3333a --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/render_app.tsx @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { AppDependencies, RootComponent } from './app'; + +interface BootDependencies extends AppDependencies { + element: HTMLElement; +} + +export const renderApp = (deps: BootDependencies) => { + const { element, ...appDependencies } = deps; + render(, element); + return () => { + unmountComponentAtNode(element); + }; +}; diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/utils.test.ts b/x-pack/plugins/upgrade_assistant/public/application/utils.test.ts similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/utils.test.ts rename to x-pack/plugins/upgrade_assistant/public/application/utils.test.ts diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/utils.ts b/x-pack/plugins/upgrade_assistant/public/application/utils.ts similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/public/np_ready/application/utils.ts rename to x-pack/plugins/upgrade_assistant/public/application/utils.ts diff --git a/x-pack/plugins/upgrade_assistant/public/index.scss b/x-pack/plugins/upgrade_assistant/public/index.scss new file mode 100644 index 0000000000000..9bd47b6473372 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/index.scss @@ -0,0 +1 @@ +@import './application/index'; diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/index.ts b/x-pack/plugins/upgrade_assistant/public/index.ts similarity index 62% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/index.ts rename to x-pack/plugins/upgrade_assistant/public/index.ts index cf1b78e1e3920..2b1860167ef5d 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/index.ts +++ b/x-pack/plugins/upgrade_assistant/public/index.ts @@ -3,9 +3,10 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { PluginInitializerContext } from 'src/core/server'; -import { UpgradeAssistantServerPlugin } from './plugin'; +import './index.scss'; +import { PluginInitializerContext } from 'src/core/public'; +import { UpgradeAssistantUIPlugin } from './plugin'; export const plugin = (ctx: PluginInitializerContext) => { - return new UpgradeAssistantServerPlugin(); + return new UpgradeAssistantUIPlugin(ctx); }; diff --git a/x-pack/plugins/upgrade_assistant/public/plugin.ts b/x-pack/plugins/upgrade_assistant/public/plugin.ts new file mode 100644 index 0000000000000..614221272dd5c --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/plugin.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { i18n } from '@kbn/i18n'; +import { Plugin, CoreSetup, PluginInitializerContext } from 'src/core/public'; + +import { CloudSetup } from '../../cloud/public'; +import { ManagementSetup } from '../../../../src/plugins/management/public'; + +import { NEXT_MAJOR_VERSION } from '../common/version'; +import { Config } from '../common/config'; + +import { renderApp } from './application/render_app'; + +interface Dependencies { + cloud: CloudSetup; + management: ManagementSetup; +} + +export class UpgradeAssistantUIPlugin implements Plugin { + constructor(private ctx: PluginInitializerContext) {} + setup({ http, getStartServices }: CoreSetup, { cloud, management }: Dependencies) { + const { enabled } = this.ctx.config.get(); + if (!enabled) { + return; + } + const appRegistrar = management.sections.getSection('elasticsearch')!; + const isCloudEnabled = Boolean(cloud?.isCloudEnabled); + + appRegistrar.registerApp({ + id: 'upgrade_assistant', + title: i18n.translate('xpack.upgradeAssistant.appTitle', { + defaultMessage: '{version} Upgrade Assistant', + values: { version: `${NEXT_MAJOR_VERSION}.0` }, + }), + order: 1000, + async mount({ element }) { + const [{ i18n: i18nDep }] = await getStartServices(); + return renderApp({ element, isCloudEnabled, http, i18n: i18nDep }); + }, + }); + } + + start() {} + stop() {} +} diff --git a/x-pack/plugins/upgrade_assistant/server/index.ts b/x-pack/plugins/upgrade_assistant/server/index.ts new file mode 100644 index 0000000000000..cab7eb613f74c --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { PluginInitializerContext, PluginConfigDescriptor } from 'src/core/server'; +import { UpgradeAssistantServerPlugin } from './plugin'; +import { configSchema } from '../common/config'; + +export const plugin = (ctx: PluginInitializerContext) => { + return new UpgradeAssistantServerPlugin(ctx); +}; + +export const config: PluginConfigDescriptor = { + schema: configSchema, + exposeToBrowser: { + enabled: true, + }, +}; diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/__fixtures__/fake_deprecations.json b/x-pack/plugins/upgrade_assistant/server/lib/__fixtures__/fake_deprecations.json similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/__fixtures__/fake_deprecations.json rename to x-pack/plugins/upgrade_assistant/server/lib/__fixtures__/fake_deprecations.json diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/__mocks__/es_version_precheck.ts b/x-pack/plugins/upgrade_assistant/server/lib/__mocks__/es_version_precheck.ts similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/__mocks__/es_version_precheck.ts rename to x-pack/plugins/upgrade_assistant/server/lib/__mocks__/es_version_precheck.ts diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/__snapshots__/es_migration_apis.test.ts.snap b/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_migration_apis.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/__snapshots__/es_migration_apis.test.ts.snap rename to x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_migration_apis.test.ts.snap diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_deprecation_logging_apis.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecation_logging_apis.test.ts similarity index 75% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_deprecation_logging_apis.test.ts rename to x-pack/plugins/upgrade_assistant/server/lib/es_deprecation_logging_apis.test.ts index 317e2a7554e03..862f64e232370 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_deprecation_logging_apis.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecation_logging_apis.test.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { getDeprecationLoggingStatus, isDeprecationLoggingEnabled, @@ -12,9 +12,9 @@ import { describe('getDeprecationLoggingStatus', () => { it('calls cluster.getSettings', async () => { - const callWithRequest = jest.fn(); - await getDeprecationLoggingStatus(callWithRequest, {} as any); - expect(callWithRequest).toHaveBeenCalledWith({}, 'cluster.getSettings', { + const dataClient = elasticsearchServiceMock.createScopedClusterClient(); + await getDeprecationLoggingStatus(dataClient); + expect(dataClient.callAsCurrentUser).toHaveBeenCalledWith('cluster.getSettings', { includeDefaults: true, }); }); @@ -23,9 +23,9 @@ describe('getDeprecationLoggingStatus', () => { describe('setDeprecationLogging', () => { describe('isEnabled = true', () => { it('calls cluster.putSettings with logger.deprecation = WARN', async () => { - const callWithRequest = jest.fn(); - await setDeprecationLogging(callWithRequest, {} as any, true); - expect(callWithRequest).toHaveBeenCalledWith({}, 'cluster.putSettings', { + const dataClient = elasticsearchServiceMock.createScopedClusterClient(); + await setDeprecationLogging(dataClient, true); + expect(dataClient.callAsCurrentUser).toHaveBeenCalledWith('cluster.putSettings', { body: { transient: { 'logger.deprecation': 'WARN' } }, }); }); @@ -33,9 +33,9 @@ describe('setDeprecationLogging', () => { describe('isEnabled = false', () => { it('calls cluster.putSettings with logger.deprecation = ERROR', async () => { - const callWithRequest = jest.fn(); - await setDeprecationLogging(callWithRequest, {} as any, false); - expect(callWithRequest).toHaveBeenCalledWith({}, 'cluster.putSettings', { + const dataClient = elasticsearchServiceMock.createScopedClusterClient(); + await setDeprecationLogging(dataClient, false); + expect(dataClient.callAsCurrentUser).toHaveBeenCalledWith('cluster.putSettings', { body: { transient: { 'logger.deprecation': 'ERROR' } }, }); }); diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_deprecation_logging_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecation_logging_apis.ts similarity index 75% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_deprecation_logging_apis.ts rename to x-pack/plugins/upgrade_assistant/server/lib/es_deprecation_logging_apis.ts index 199d389408442..8f25533c0afb1 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_deprecation_logging_apis.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecation_logging_apis.ts @@ -4,19 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ import { get } from 'lodash'; - -import { CallClusterWithRequest } from 'src/legacy/core_plugins/elasticsearch'; -import { RequestShim } from '../types'; +import { IScopedClusterClient } from 'src/core/server'; interface DeprecationLoggingStatus { isEnabled: boolean; } export async function getDeprecationLoggingStatus( - callWithRequest: CallClusterWithRequest, - req: RequestShim + dataClient: IScopedClusterClient ): Promise { - const response = await callWithRequest(req, 'cluster.getSettings', { + const response = await dataClient.callAsCurrentUser('cluster.getSettings', { includeDefaults: true, }); @@ -26,11 +23,10 @@ export async function getDeprecationLoggingStatus( } export async function setDeprecationLogging( - callWithRequest: CallClusterWithRequest, - req: RequestShim, + dataClient: IScopedClusterClient, isEnabled: boolean ): Promise { - const response = await callWithRequest(req, 'cluster.putSettings', { + const response = await dataClient.callAsCurrentUser('cluster.putSettings', { body: { transient: { 'logger.deprecation': isEnabled ? 'WARN' : 'ERROR', diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_migration_apis.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts similarity index 73% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_migration_apis.test.ts rename to x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts index a1d7049e4171f..4ab4227ba3e91 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_migration_apis.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts @@ -5,6 +5,7 @@ */ import _ from 'lodash'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { getUpgradeAssistantStatus } from './es_migration_apis'; import { DeprecationAPIResponse } from 'src/legacy/core_plugins/elasticsearch'; @@ -13,7 +14,8 @@ import fakeDeprecations from './__fixtures__/fake_deprecations.json'; describe('getUpgradeAssistantStatus', () => { let deprecationsResponse: DeprecationAPIResponse; - const callWithRequest = jest.fn().mockImplementation(async (req, api, { path }) => { + const dataClient = elasticsearchServiceMock.createScopedClusterClient(); + (dataClient.callAsCurrentUser as jest.Mock).mockImplementation(async (api, { path }) => { if (path === '/_migration/deprecations') { return deprecationsResponse; } else if (api === 'indices.getMapping') { @@ -28,15 +30,15 @@ describe('getUpgradeAssistantStatus', () => { }); it('calls /_migration/deprecations', async () => { - await getUpgradeAssistantStatus(callWithRequest, {} as any, false); - expect(callWithRequest).toHaveBeenCalledWith({}, 'transport.request', { + await getUpgradeAssistantStatus(dataClient, false); + expect(dataClient.callAsCurrentUser).toHaveBeenCalledWith('transport.request', { path: '/_migration/deprecations', method: 'GET', }); }); it('returns the correct shape of data', async () => { - const resp = await getUpgradeAssistantStatus(callWithRequest, {} as any, false); + const resp = await getUpgradeAssistantStatus(dataClient, false); expect(resp).toMatchSnapshot(); }); @@ -48,9 +50,10 @@ describe('getUpgradeAssistantStatus', () => { index_settings: {}, }; - await expect( - getUpgradeAssistantStatus(callWithRequest, {} as any, false) - ).resolves.toHaveProperty('readyForUpgrade', false); + await expect(getUpgradeAssistantStatus(dataClient, false)).resolves.toHaveProperty( + 'readyForUpgrade', + false + ); }); it('returns readyForUpgrade === true when no critical issues found', async () => { @@ -61,9 +64,10 @@ describe('getUpgradeAssistantStatus', () => { index_settings: {}, }; - await expect( - getUpgradeAssistantStatus(callWithRequest, {} as any, false) - ).resolves.toHaveProperty('readyForUpgrade', true); + await expect(getUpgradeAssistantStatus(dataClient, false)).resolves.toHaveProperty( + 'readyForUpgrade', + true + ); }); it('filters out security realm deprecation on Cloud', async () => { @@ -80,7 +84,7 @@ describe('getUpgradeAssistantStatus', () => { index_settings: {}, }; - const result = await getUpgradeAssistantStatus(callWithRequest, {} as any, true); + const result = await getUpgradeAssistantStatus(dataClient, true); expect(result).toHaveProperty('readyForUpgrade', true); expect(result).toHaveProperty('cluster', []); diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_migration_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts similarity index 75% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_migration_apis.ts rename to x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts index b52c4c374266f..68f21c1fd93b5 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_migration_apis.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts @@ -4,32 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - CallClusterWithRequest, - DeprecationAPIResponse, - DeprecationInfo, -} from 'src/legacy/core_plugins/elasticsearch'; - -import { RequestShim } from '../types'; - -export interface EnrichedDeprecationInfo extends DeprecationInfo { - index?: string; - node?: string; - reindex?: boolean; -} - -export interface UpgradeAssistantStatus { - readyForUpgrade: boolean; - cluster: EnrichedDeprecationInfo[]; - indices: EnrichedDeprecationInfo[]; -} +import { IScopedClusterClient } from 'src/core/server'; +import { DeprecationAPIResponse } from 'src/legacy/core_plugins/elasticsearch'; +import { EnrichedDeprecationInfo, UpgradeAssistantStatus } from '../../common/types'; export async function getUpgradeAssistantStatus( - callWithRequest: CallClusterWithRequest, - req: RequestShim, + dataClient: IScopedClusterClient, isCloudEnabled: boolean ): Promise { - const deprecations = await callWithRequest(req, 'transport.request', { + const deprecations = await dataClient.callAsCurrentUser('transport.request', { path: '/_migration/deprecations', method: 'GET', }); diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_version_precheck.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_version_precheck.test.ts similarity index 98% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_version_precheck.test.ts rename to x-pack/plugins/upgrade_assistant/server/lib/es_version_precheck.test.ts index bbabe557df4d4..51cb776ef4e0b 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_version_precheck.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_version_precheck.test.ts @@ -6,7 +6,7 @@ import { SemVer } from 'semver'; import { IScopedClusterClient, kibanaResponseFactory } from 'src/core/server'; -import { CURRENT_VERSION } from '../../../common/version'; +import { CURRENT_VERSION } from '../../common/version'; import { esVersionCheck, getAllNodeVersions, diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_version_precheck.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_version_precheck.ts similarity index 98% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_version_precheck.ts rename to x-pack/plugins/upgrade_assistant/server/lib/es_version_precheck.ts index 2fb3effe43793..e7636eea66479 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/es_version_precheck.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_version_precheck.ts @@ -13,7 +13,7 @@ import { RequestHandler, RequestHandlerContext, } from 'src/core/server'; -import { CURRENT_VERSION } from '../../../common/version'; +import { CURRENT_VERSION } from '../../common/version'; /** * Returns an array of all the unique Elasticsearch Node Versions in the Elasticsearch cluster. diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/credential_store.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/credential_store.test.ts similarity index 95% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/credential_store.test.ts rename to x-pack/plugins/upgrade_assistant/server/lib/reindexing/credential_store.test.ts index 06fa755472238..ce892df0de946 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/credential_store.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/credential_store.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ReindexSavedObject } from '../../../../common/types'; +import { ReindexSavedObject } from '../../../common/types'; import { Credential, credentialStoreFactory } from './credential_store'; describe('credentialStore', () => { diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/credential_store.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/credential_store.ts similarity index 91% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/credential_store.ts rename to x-pack/plugins/upgrade_assistant/server/lib/reindexing/credential_store.ts index a051d16b5779f..0958559910be6 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/credential_store.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/credential_store.ts @@ -5,12 +5,11 @@ */ import { createHash } from 'crypto'; -import { Request } from 'hapi'; import stringify from 'json-stable-stringify'; -import { ReindexSavedObject } from '../../../../common/types'; +import { ReindexSavedObject } from '../../../common/types'; -export type Credential = Request['headers']; +export type Credential = Record; /** * An in-memory cache for user credentials to be used for reindexing operations. When looking up diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/index.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/index.ts similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/index.ts rename to x-pack/plugins/upgrade_assistant/server/lib/reindexing/index.ts diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/index_settings.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/index_settings.test.ts similarity index 99% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/index_settings.test.ts rename to x-pack/plugins/upgrade_assistant/server/lib/reindexing/index_settings.test.ts index 7b346cc87edf6..9ec06b72f02e2 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/index_settings.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/index_settings.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CURRENT_MAJOR_VERSION, PREV_MAJOR_VERSION } from '../../../../common/version'; +import { CURRENT_MAJOR_VERSION, PREV_MAJOR_VERSION } from '../../../common/version'; import { generateNewIndexName, getReindexWarnings, diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/index_settings.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/index_settings.ts similarity index 97% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/index_settings.ts rename to x-pack/plugins/upgrade_assistant/server/lib/reindexing/index_settings.ts index 0b95bc628fbb4..f6dc471d0945d 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/index_settings.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/index_settings.ts @@ -5,8 +5,8 @@ */ import { flow, omit } from 'lodash'; -import { ReindexWarning } from '../../../../common/types'; -import { CURRENT_MAJOR_VERSION, PREV_MAJOR_VERSION } from '../../../../common/version'; +import { ReindexWarning } from '../../../common/types'; +import { CURRENT_MAJOR_VERSION, PREV_MAJOR_VERSION } from '../../../common/version'; import { FlatSettings } from './types'; export interface ParsedIndexName { diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/reindex_actions.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_actions.test.ts similarity index 99% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/reindex_actions.test.ts rename to x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_actions.test.ts index 3fb855958a5d0..4569fdfa33a83 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/reindex_actions.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_actions.test.ts @@ -13,8 +13,8 @@ import { ReindexSavedObject, ReindexStatus, ReindexStep, -} from '../../../../common/types'; -import { CURRENT_MAJOR_VERSION, PREV_MAJOR_VERSION } from '../../../../common/version'; +} from '../../../common/types'; +import { CURRENT_MAJOR_VERSION, PREV_MAJOR_VERSION } from '../../../common/version'; import { LOCK_WINDOW, ReindexActions, reindexActionsFactory } from './reindex_actions'; describe('ReindexActions', () => { diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/reindex_actions.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_actions.ts similarity index 97% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/reindex_actions.ts rename to x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_actions.ts index 6683f80c8e779..2ae340f12d80c 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/reindex_actions.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_actions.ts @@ -6,8 +6,7 @@ import moment from 'moment'; -import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; -import { SavedObjectsFindResponse, SavedObjectsClientContract } from 'kibana/server'; +import { SavedObjectsFindResponse, SavedObjectsClientContract, APICaller } from 'src/core/server'; import { IndexGroup, REINDEX_OP_TYPE, @@ -15,7 +14,7 @@ import { ReindexSavedObject, ReindexStatus, ReindexStep, -} from '../../../../common/types'; +} from '../../../common/types'; import { generateNewIndexName } from './index_settings'; import { FlatSettings } from './types'; @@ -111,7 +110,7 @@ export interface ReindexActions { export const reindexActionsFactory = ( client: SavedObjectsClientContract, - callCluster: CallCluster + callAsUser: APICaller ): ReindexActions => { // ----- Internal functions const isLocked = (reindexOp: ReindexSavedObject) => { @@ -230,7 +229,7 @@ export const reindexActionsFactory = ( }, async getFlatSettings(indexName: string) { - const flatSettings = (await callCluster('transport.request', { + const flatSettings = (await callAsUser('transport.request', { path: `/${encodeURIComponent(indexName)}?flat_settings=true`, })) as { [indexName: string]: FlatSettings }; diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/reindex_service.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts similarity index 95% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/reindex_service.test.ts rename to x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts index 9cd41c8cbe826..6c3b2c869dc7f 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/reindex_service.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts @@ -4,14 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ +import { BehaviorSubject } from 'rxjs'; +import { Logger } from 'src/core/server'; +import { loggingServiceMock } from 'src/core/server/mocks'; + import { IndexGroup, ReindexOperation, ReindexSavedObject, ReindexStatus, ReindexStep, -} from '../../../../common/types'; -import { CURRENT_MAJOR_VERSION, PREV_MAJOR_VERSION } from '../../../../common/version'; +} from '../../../common/types'; +import { CURRENT_MAJOR_VERSION, PREV_MAJOR_VERSION } from '../../../common/version'; +import { licensingMock } from '../../../../licensing/server/mocks'; +import { LicensingPluginSetup } from '../../../../licensing/server'; + import { isMlIndex, isWatcherIndex, @@ -22,9 +29,9 @@ import { describe('reindexService', () => { let actions: jest.Mocked; let callCluster: jest.Mock; - let log: jest.Mock; - let xpackInfo: { feature: jest.Mocked }; + let log: Logger; let service: ReindexService; + let licensingPluginSetup: LicensingPluginSetup; const updateMockImpl = (reindexOp: ReindexSavedObject, attrs: Partial = {}) => Promise.resolve({ @@ -50,32 +57,24 @@ describe('reindexService', () => { runWhileIndexGroupLocked: jest.fn(async (group: string, f: any) => f({ attributes: {} })), }; callCluster = jest.fn(); - log = jest.fn(); - xpackInfo = { - feature: jest.fn(() => ({ - isAvailable() { - return true; - }, - isEnabled() { - return true; - }, - })), - }; - - service = reindexServiceFactory(callCluster as any, xpackInfo as any, actions, log); + log = loggingServiceMock.create().get(); + licensingPluginSetup = licensingMock.createSetup(); + licensingPluginSetup.license$ = new BehaviorSubject( + licensingMock.createLicense({ + features: { security: { isAvailable: true, isEnabled: true } }, + }) + ); + + service = reindexServiceFactory(callCluster as any, actions, log, licensingPluginSetup); }); describe('hasRequiredPrivileges', () => { it('returns true if security is disabled', async () => { - xpackInfo.feature.mockReturnValueOnce({ - isAvailable() { - return true; - }, - isEnabled() { - return false; - }, - }); - + licensingPluginSetup.license$ = new BehaviorSubject( + licensingMock.createLicense({ + features: { security: { isAvailable: true, isEnabled: false } }, + }) + ); const hasRequired = await service.hasRequiredPrivileges('anIndex'); expect(hasRequired).toBe(true); }); @@ -584,7 +583,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.created); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage!.includes(`Can't lock!`)).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); expect(callCluster).not.toHaveBeenCalledWith('transport.request', { path: '/_ml/set_upgrade_mode?enabled=true', method: 'POST', @@ -599,7 +598,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.created); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage!.includes(`Can't lock!`)).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); expect(callCluster).not.toHaveBeenCalledWith('transport.request', { path: '/_ml/set_upgrade_mode?enabled=true', method: 'POST', @@ -623,7 +622,7 @@ describe('reindexService', () => { expect( updatedOp.attributes.errorMessage!.includes('Could not stop ML jobs') ).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); expect(callCluster).toHaveBeenCalledWith('transport.request', { path: '/_ml/set_upgrade_mode?enabled=true', method: 'POST', @@ -645,7 +644,7 @@ describe('reindexService', () => { expect( updatedOp.attributes.errorMessage!.includes('Some nodes are not on minimum version') ).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); // Should not have called ML endpoint at all expect(callCluster).not.toHaveBeenCalledWith('transport.request', { path: '/_ml/set_upgrade_mode?enabled=true', @@ -698,7 +697,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.created); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage!.includes(`Can't lock!`)).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); expect(callCluster).not.toHaveBeenCalledWith('transport.request', { path: '/_watcher/_stop', method: 'POST', @@ -713,7 +712,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.created); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage!.includes(`Can't lock!`)).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); expect(callCluster).not.toHaveBeenCalledWith('transport.request', { path: '/_watcher/_stop', method: 'POST', @@ -735,7 +734,7 @@ describe('reindexService', () => { expect( updatedOp.attributes.errorMessage!.includes('Could not stop Watcher') ).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); expect(callCluster).toHaveBeenCalledWith('transport.request', { path: '/_watcher/_stop', method: 'POST', @@ -771,7 +770,7 @@ describe('reindexService', () => { ); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage).not.toBeNull(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); }); it('fails if setting updates fail', async () => { @@ -782,7 +781,7 @@ describe('reindexService', () => { ); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage).not.toBeNull(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); }); }); @@ -817,7 +816,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.readonly); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage).not.toBeNull(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); }); it('fails if create index fails', async () => { @@ -829,7 +828,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.readonly); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage).not.toBeNull(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); // Original index should have been set back to allow reads. expect(callCluster).toHaveBeenCalledWith('indices.putSettings', { @@ -874,7 +873,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.newIndexCreated); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage).not.toBeNull(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); }); }); @@ -931,7 +930,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.reindexStarted); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage).not.toBeNull(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); }); }); @@ -1014,7 +1013,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.reindexCompleted); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage).not.toBeNull(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); }); it('fails if switching aliases fails', async () => { @@ -1023,7 +1022,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.reindexCompleted); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage).not.toBeNull(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); }); }); @@ -1092,7 +1091,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.aliasCreated); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage!.includes(`Can't lock!`)).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); expect(callCluster).not.toHaveBeenCalledWith('transport.request', { path: '/_ml/set_upgrade_mode?enabled=false', method: 'POST', @@ -1108,7 +1107,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.aliasCreated); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage!.includes(`Can't lock!`)).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); expect(callCluster).not.toHaveBeenCalledWith('transport.request', { path: '/_ml/set_upgrade_mode?enabled=false', method: 'POST', @@ -1129,7 +1128,7 @@ describe('reindexService', () => { expect( updatedOp.attributes.errorMessage!.includes('Could not resume ML jobs') ).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); expect(callCluster).toHaveBeenCalledWith('transport.request', { path: '/_ml/set_upgrade_mode?enabled=false', method: 'POST', @@ -1196,7 +1195,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.aliasCreated); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage!.includes(`Can't lock!`)).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); expect(callCluster).not.toHaveBeenCalledWith('transport.request', { path: '/_watcher/_start', method: 'POST', @@ -1212,7 +1211,7 @@ describe('reindexService', () => { expect(updatedOp.attributes.lastCompletedStep).toEqual(ReindexStep.aliasCreated); expect(updatedOp.attributes.status).toEqual(ReindexStatus.failed); expect(updatedOp.attributes.errorMessage!.includes(`Can't lock!`)).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); expect(callCluster).not.toHaveBeenCalledWith('transport.request', { path: '/_watcher/_start', method: 'POST', @@ -1233,7 +1232,7 @@ describe('reindexService', () => { expect( updatedOp.attributes.errorMessage!.includes('Could not start Watcher') ).toBeTruthy(); - expect(log).toHaveBeenCalledWith(['upgrade_assistant', 'error'], expect.any(String)); + expect(log.error).toHaveBeenCalledWith(expect.any(String)); expect(callCluster).toHaveBeenCalledWith('transport.request', { path: '/_watcher/_start', method: 'POST', diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/reindex_service.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts similarity index 90% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/reindex_service.ts rename to x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts index 0e6095f98b6ff..8f1df5b34372b 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/reindex_service.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts @@ -5,17 +5,16 @@ */ import Boom from 'boom'; +import { APICaller, Logger } from 'src/core/server'; +import { first } from 'rxjs/operators'; -import { Server } from 'hapi'; -import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; -import { XPackInfo } from '../../../../../xpack_main/server/lib/xpack_info'; import { IndexGroup, ReindexSavedObject, ReindexStatus, ReindexStep, ReindexWarning, -} from '../../../../common/types'; +} from '../../../common/types'; import { generateNewIndexName, getReindexWarnings, @@ -23,6 +22,7 @@ import { transformFlatSettings, } from './index_settings'; import { ReindexActions } from './reindex_actions'; +import { LicensingPluginSetup } from '../../../../licensing/server'; const VERSION_REGEX = new RegExp(/^([1-9]+)\.([0-9]+)\.([0-9]+)/); const ML_INDICES = ['.ml-state', '.ml-anomalies', '.ml-config']; @@ -97,10 +97,10 @@ export interface ReindexService { } export const reindexServiceFactory = ( - callCluster: CallCluster, - xpackInfo: XPackInfo, + callAsUser: APICaller, actions: ReindexActions, - log: Server['log'] + log: Logger, + licensing: LicensingPluginSetup ): ReindexService => { // ------ Utility functions @@ -114,7 +114,7 @@ export const reindexServiceFactory = ( await actions.runWhileIndexGroupLocked(IndexGroup.ml, async mlDoc => { await validateNodesMinimumVersion(6, 7); - const res = await callCluster('transport.request', { + const res = await callAsUser('transport.request', { path: '/_ml/set_upgrade_mode?enabled=true', method: 'POST', }); @@ -134,7 +134,7 @@ export const reindexServiceFactory = ( await actions.decrementIndexGroupReindexes(IndexGroup.ml); await actions.runWhileIndexGroupLocked(IndexGroup.ml, async mlDoc => { if (mlDoc.attributes.runningReindexCount === 0) { - const res = await callCluster('transport.request', { + const res = await callAsUser('transport.request', { path: '/_ml/set_upgrade_mode?enabled=false', method: 'POST', }); @@ -154,7 +154,7 @@ export const reindexServiceFactory = ( const stopWatcher = async () => { await actions.incrementIndexGroupReindexes(IndexGroup.watcher); await actions.runWhileIndexGroupLocked(IndexGroup.watcher, async watcherDoc => { - const { acknowledged } = await callCluster('transport.request', { + const { acknowledged } = await callAsUser('transport.request', { path: '/_watcher/_stop', method: 'POST', }); @@ -174,7 +174,7 @@ export const reindexServiceFactory = ( await actions.decrementIndexGroupReindexes(IndexGroup.watcher); await actions.runWhileIndexGroupLocked(IndexGroup.watcher, async watcherDoc => { if (watcherDoc.attributes.runningReindexCount === 0) { - const { acknowledged } = await callCluster('transport.request', { + const { acknowledged } = await callAsUser('transport.request', { path: '/_watcher/_start', method: 'POST', }); @@ -191,14 +191,14 @@ export const reindexServiceFactory = ( const cleanupChanges = async (reindexOp: ReindexSavedObject) => { // Cancel reindex task if it was started but not completed if (reindexOp.attributes.lastCompletedStep === ReindexStep.reindexStarted) { - await callCluster('tasks.cancel', { + await callAsUser('tasks.cancel', { taskId: reindexOp.attributes.reindexTaskId, }).catch(e => undefined); // Ignore any exceptions trying to cancel (it may have already completed). } // Set index back to writable if we ever got past this point. if (reindexOp.attributes.lastCompletedStep >= ReindexStep.readonly) { - await callCluster('indices.putSettings', { + await callAsUser('indices.putSettings', { index: reindexOp.attributes.indexName, body: { 'index.blocks.write': false }, }); @@ -208,7 +208,7 @@ export const reindexServiceFactory = ( reindexOp.attributes.lastCompletedStep >= ReindexStep.newIndexCreated && reindexOp.attributes.lastCompletedStep < ReindexStep.aliasCreated ) { - await callCluster('indices.delete', { index: reindexOp.attributes.newIndexName }); + await callAsUser('indices.delete', { index: reindexOp.attributes.newIndexName }); } // Resume consumers if we ever got past this point. @@ -222,7 +222,7 @@ export const reindexServiceFactory = ( // ------ Functions used to process the state machine const validateNodesMinimumVersion = async (minMajor: number, minMinor: number) => { - const nodesResponse = await callCluster('transport.request', { + const nodesResponse = await callAsUser('transport.request', { path: '/_nodes', method: 'GET', }); @@ -263,7 +263,7 @@ export const reindexServiceFactory = ( */ const setReadonly = async (reindexOp: ReindexSavedObject) => { const { indexName } = reindexOp.attributes; - const putReadonly = await callCluster('indices.putSettings', { + const putReadonly = await callAsUser('indices.putSettings', { index: indexName, body: { 'index.blocks.write': true }, }); @@ -289,7 +289,7 @@ export const reindexServiceFactory = ( const { settings, mappings } = transformFlatSettings(flatSettings); - const createIndex = await callCluster('indices.create', { + const createIndex = await callAsUser('indices.create', { index: newIndexName, body: { settings, @@ -313,7 +313,7 @@ export const reindexServiceFactory = ( const startReindexing = async (reindexOp: ReindexSavedObject) => { const { indexName } = reindexOp.attributes; - const startReindex = (await callCluster('reindex', { + const startReindex = (await callAsUser('reindex', { refresh: true, waitForCompletion: false, body: { @@ -337,7 +337,7 @@ export const reindexServiceFactory = ( const taskId = reindexOp.attributes.reindexTaskId; // Check reindexing task progress - const taskResponse = await callCluster('tasks.get', { + const taskResponse = await callAsUser('tasks.get', { taskId, waitForCompletion: false, }); @@ -358,7 +358,7 @@ export const reindexServiceFactory = ( reindexOp = await cleanupChanges(reindexOp); } else { // Check that it reindexed all documents - const { count } = await callCluster('count', { index: reindexOp.attributes.indexName }); + const { count } = await callAsUser('count', { index: reindexOp.attributes.indexName }); if (taskResponse.task.status.created < count) { // Include the entire task result in the error message. This should be guaranteed @@ -374,7 +374,7 @@ export const reindexServiceFactory = ( } // Delete the task from ES .tasks index - const deleteTaskResp = await callCluster('delete', { + const deleteTaskResp = await callAsUser('delete', { index: '.tasks', id: taskId, }); @@ -394,7 +394,7 @@ export const reindexServiceFactory = ( const { indexName, newIndexName } = reindexOp.attributes; const existingAliases = ( - await callCluster('indices.getAlias', { + await callAsUser('indices.getAlias', { index: indexName, }) )[indexName].aliases; @@ -403,7 +403,7 @@ export const reindexServiceFactory = ( add: { index: newIndexName, alias: aliasName, ...existingAliases[aliasName] }, })); - const aliasResponse = await callCluster('indices.updateAliases', { + const aliasResponse = await callAsUser('indices.updateAliases', { body: { actions: [ { add: { index: newIndexName, alias: indexName } }, @@ -443,9 +443,18 @@ export const reindexServiceFactory = ( return { async hasRequiredPrivileges(indexName: string) { + /** + * To avoid a circular dependency on Security we use a work around + * here to detect whether Security is available and enabled + * (i.e., via the licensing plugin). This enables Security to use + * functionality exposed through Upgrade Assistant. + */ + const license = await licensing.license$.pipe(first()).toPromise(); + + const securityFeature = license.getFeature('security'); + // If security is disabled or unavailable, return true. - const security = xpackInfo.feature('security'); - if (!security.isAvailable() || !security.isEnabled()) { + if (!securityFeature || !(securityFeature.isAvailable && securityFeature.isEnabled)) { return true; } @@ -482,7 +491,7 @@ export const reindexServiceFactory = ( body.cluster = [...body.cluster, 'manage_watcher']; } - const resp = await callCluster('transport.request', { + const resp = await callAsUser('transport.request', { path: '/_security/user/_has_privileges', method: 'POST', body, @@ -509,7 +518,7 @@ export const reindexServiceFactory = ( }, async createReindexOperation(indexName: string) { - const indexExists = await callCluster('indices.exists', { index: indexName }); + const indexExists = await callAsUser('indices.exists', { index: indexName }); if (!indexExists) { throw Boom.notFound(`Index ${indexName} does not exist in this cluster.`); } @@ -579,10 +588,7 @@ export const reindexServiceFactory = ( break; } } catch (e) { - log( - ['upgrade_assistant', 'error'], - `Reindexing step failed: ${e instanceof Error ? e.stack : e.toString()}` - ); + log.error(`Reindexing step failed: ${e instanceof Error ? e.stack : e.toString()}`); // Trap the exception and add the message to the object so the UI can display it. lockedReindexOp = await actions.updateReindexOp(lockedReindexOp, { @@ -647,7 +653,7 @@ export const reindexServiceFactory = ( throw new Error(`Reindex operation is not current waiting for reindex task to complete`); } - const resp = await callCluster('tasks.cancel', { + const resp = await callAsUser('tasks.cancel', { taskId: reindexOp.attributes.reindexTaskId, }); diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/types.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/types.ts similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/types.ts rename to x-pack/plugins/upgrade_assistant/server/lib/reindexing/types.ts diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/worker.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/worker.ts similarity index 76% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/worker.ts rename to x-pack/plugins/upgrade_assistant/server/lib/reindexing/worker.ts index 628a47be9f5e7..bad6db62efe41 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/reindexing/worker.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/worker.ts @@ -3,23 +3,19 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { CallCluster, CallClusterWithRequest } from 'src/legacy/core_plugins/elasticsearch'; -import { Request, Server } from 'src/legacy/server/kbn_server'; -import { SavedObjectsClientContract } from 'kibana/server'; - +import { IClusterClient, Logger, SavedObjectsClientContract, FakeRequest } from 'src/core/server'; import moment from 'moment'; -import { XPackInfo } from '../../../../../xpack_main/server/lib/xpack_info'; -import { ReindexSavedObject, ReindexStatus } from '../../../../common/types'; + +import { ReindexSavedObject, ReindexStatus } from '../../../common/types'; import { CredentialStore } from './credential_store'; import { reindexActionsFactory } from './reindex_actions'; import { ReindexService, reindexServiceFactory } from './reindex_service'; +import { LicensingPluginSetup } from '../../../../licensing/server'; const POLL_INTERVAL = 30000; // If no nodes have been able to update this index in 2 minutes (due to missing credentials), set to paused. const PAUSE_WINDOW = POLL_INTERVAL * 4; -const LOG_TAGS = ['upgrade_assistant', 'reindex_worker']; - /** * A singleton worker that will coordinate two polling loops: * (1) A longer loop that polls for reindex operations that are in progress. If any are found, loop (2) is started. @@ -41,24 +37,27 @@ export class ReindexWorker { private timeout?: NodeJS.Timeout; private inProgressOps: ReindexSavedObject[] = []; private readonly reindexService: ReindexService; + private readonly log: Logger; constructor( private client: SavedObjectsClientContract, private credentialStore: CredentialStore, - private callWithRequest: CallClusterWithRequest, - private callWithInternalUser: CallCluster, - private xpackInfo: XPackInfo, - private readonly log: Server['log'] + private clusterClient: IClusterClient, + log: Logger, + private licensing: LicensingPluginSetup ) { + this.log = log.get('reindex_worker'); if (ReindexWorker.workerSingleton) { throw new Error(`More than one ReindexWorker cannot be created.`); } + const callAsInternalUser = this.clusterClient.callAsInternalUser.bind(this.clusterClient); + this.reindexService = reindexServiceFactory( - this.callWithInternalUser, - this.xpackInfo, - reindexActionsFactory(this.client, this.callWithInternalUser), - this.log + callAsInternalUser, + reindexActionsFactory(this.client, callAsInternalUser), + log, + this.licensing ); ReindexWorker.workerSingleton = this; @@ -68,7 +67,7 @@ export class ReindexWorker { * Begins loop (1) to begin checking for in progress reindex operations. */ public start = () => { - this.log(['debug', ...LOG_TAGS], `Starting worker...`); + this.log.debug('Starting worker...'); this.continuePolling = true; this.pollForOperations(); }; @@ -77,7 +76,7 @@ export class ReindexWorker { * Stops the worker from processing any further reindex operations. */ public stop = () => { - this.log(['debug', ...LOG_TAGS], `Stopping worker...`); + this.log.debug('Stopping worker...'); if (this.timeout) { clearTimeout(this.timeout); } @@ -107,7 +106,7 @@ export class ReindexWorker { this.updateOperationLoopRunning = true; while (this.inProgressOps.length > 0) { - this.log(['debug', ...LOG_TAGS], `Updating ${this.inProgressOps.length} reindex operations`); + this.log.debug(`Updating ${this.inProgressOps.length} reindex operations`); // Push each operation through the state machine and refresh. await Promise.all(this.inProgressOps.map(this.processNextStep)); @@ -118,7 +117,7 @@ export class ReindexWorker { }; private pollForOperations = async () => { - this.log(['debug', ...LOG_TAGS], `Polling for reindex operations`); + this.log.debug(`Polling for reindex operations`); await this.refresh(); @@ -131,7 +130,7 @@ export class ReindexWorker { try { this.inProgressOps = await this.reindexService.findAllByStatus(ReindexStatus.inProgress); } catch (e) { - this.log(['debug', ...LOG_TAGS], `Could not fetch riendex operations from Elasticsearch`); + this.log.debug(`Could not fetch reindex operations from Elasticsearch`); this.inProgressOps = []; } @@ -159,10 +158,13 @@ export class ReindexWorker { } // Setup a ReindexService specific to these credentials. - const fakeRequest = { headers: credential } as Request; - const callCluster = this.callWithRequest.bind(null, fakeRequest) as CallCluster; - const actions = reindexActionsFactory(this.client, callCluster); - const service = reindexServiceFactory(callCluster, this.xpackInfo, actions, this.log); + const fakeRequest: FakeRequest = { headers: credential }; + + const scopedClusterClient = this.clusterClient.asScoped(fakeRequest); + const callAsCurrentUser = scopedClusterClient.callAsCurrentUser.bind(scopedClusterClient); + const actions = reindexActionsFactory(this.client, callAsCurrentUser); + + const service = reindexServiceFactory(callAsCurrentUser, actions, this.log, this.licensing); reindexOp = await swallowExceptions(service.processNextStep, this.log)(reindexOp); // Update credential store with most recent state. @@ -176,18 +178,15 @@ export class ReindexWorker { */ const swallowExceptions = ( func: (reindexOp: ReindexSavedObject) => Promise, - log: Server['log'] + log: Logger ) => async (reindexOp: ReindexSavedObject) => { try { return await func(reindexOp); } catch (e) { if (reindexOp.attributes.locked) { - log(['debug', ...LOG_TAGS], `Skipping reindexOp with unexpired lock: ${reindexOp.id}`); + log.debug(`Skipping reindexOp with unexpired lock: ${reindexOp.id}`); } else { - log( - ['warning', ...LOG_TAGS], - `Error when trying to process reindexOp (${reindexOp.id}): ${e.toString()}` - ); + log.warn(`Error when trying to process reindexOp (${reindexOp.id}): ${e.toString()}`); } return reindexOp; diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_open_apis.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts similarity index 51% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_open_apis.test.ts rename to x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts index 5f95f6e9fd555..703351c45ba5a 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_open_apis.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.test.ts @@ -3,8 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { savedObjectsRepositoryMock } from 'src/core/server/mocks'; +import { UPGRADE_ASSISTANT_DOC_ID, UPGRADE_ASSISTANT_TYPE } from '../../../common/types'; -import { UPGRADE_ASSISTANT_DOC_ID, UPGRADE_ASSISTANT_TYPE } from '../../../../common/types'; import { upsertUIOpenOption } from './es_ui_open_apis'; /** @@ -13,54 +14,29 @@ import { upsertUIOpenOption } from './es_ui_open_apis'; * more thoroughly in the lib/telemetry tests. */ describe('Upgrade Assistant Telemetry SavedObject UIOpen', () => { - const mockIncrementCounter = jest.fn(); - const server = jest.fn().mockReturnValue({ - savedObjects: { - getSavedObjectsRepository: jest.fn().mockImplementation(() => { - return { - incrementCounter: mockIncrementCounter, - }; - }), - }, - plugins: { - elasticsearch: { - getCluster: () => { - return { - callWithInternalUser: {}, - }; - }, - }, - }, - }); - - const request = jest.fn().mockReturnValue({ - payload: { - overview: true, - cluster: true, - indices: true, - }, - }); - describe('Upsert UIOpen Option', () => { it('call saved objects internal repository with the correct info', async () => { - const serverMock = server(); - const incCounterSORepoFunc = serverMock.savedObjects.getSavedObjectsRepository() - .incrementCounter; + const internalRepo = savedObjectsRepositoryMock.create(); - await upsertUIOpenOption(serverMock, request()); + await upsertUIOpenOption({ + overview: true, + cluster: true, + indices: true, + savedObjects: { createInternalRepository: () => internalRepo } as any, + }); - expect(incCounterSORepoFunc).toHaveBeenCalledTimes(3); - expect(incCounterSORepoFunc).toHaveBeenCalledWith( + expect(internalRepo.incrementCounter).toHaveBeenCalledTimes(3); + expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, `ui_open.overview` ); - expect(incCounterSORepoFunc).toHaveBeenCalledWith( + expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, `ui_open.cluster` ); - expect(incCounterSORepoFunc).toHaveBeenCalledWith( + expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, `ui_open.indices` diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.ts new file mode 100644 index 0000000000000..64e9b0f217555 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_open_apis.ts @@ -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 { SavedObjectsServiceStart } from 'src/core/server'; +import { + UIOpen, + UIOpenOption, + UPGRADE_ASSISTANT_DOC_ID, + UPGRADE_ASSISTANT_TYPE, +} from '../../../common/types'; + +interface IncrementUIOpenDependencies { + uiOpenOptionCounter: UIOpenOption; + savedObjects: SavedObjectsServiceStart; +} + +async function incrementUIOpenOptionCounter({ + savedObjects, + uiOpenOptionCounter, +}: IncrementUIOpenDependencies) { + const internalRepository = savedObjects.createInternalRepository(); + + await internalRepository.incrementCounter( + UPGRADE_ASSISTANT_TYPE, + UPGRADE_ASSISTANT_DOC_ID, + `ui_open.${uiOpenOptionCounter}` + ); +} + +type UpsertUIOpenOptionDependencies = UIOpen & { savedObjects: SavedObjectsServiceStart }; + +export async function upsertUIOpenOption({ + overview, + cluster, + indices, + savedObjects, +}: UpsertUIOpenOptionDependencies): Promise { + if (overview) { + await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'overview' }); + } + + if (cluster) { + await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'cluster' }); + } + + if (indices) { + await incrementUIOpenOptionCounter({ savedObjects, uiOpenOptionCounter: 'indices' }); + } + + return { + overview, + cluster, + indices, + }; +} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_reindex_apis.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.test.ts similarity index 52% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_reindex_apis.test.ts rename to x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.test.ts index 3f2c80f7d6b75..31e4e3f07b5de 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/es_ui_reindex_apis.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.test.ts @@ -3,8 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - -import { UPGRADE_ASSISTANT_DOC_ID, UPGRADE_ASSISTANT_TYPE } from '../../../../common/types'; +import { savedObjectsRepositoryMock } from 'src/core/server/mocks'; +import { UPGRADE_ASSISTANT_DOC_ID, UPGRADE_ASSISTANT_TYPE } from '../../../common/types'; import { upsertUIReindexOption } from './es_ui_reindex_apis'; /** @@ -13,60 +13,34 @@ import { upsertUIReindexOption } from './es_ui_reindex_apis'; * more thoroughly in the lib/telemetry tests. */ describe('Upgrade Assistant Telemetry SavedObject UIReindex', () => { - const mockIncrementCounter = jest.fn(); - const server = jest.fn().mockReturnValue({ - savedObjects: { - getSavedObjectsRepository: jest.fn().mockImplementation(() => { - return { - incrementCounter: mockIncrementCounter, - }; - }), - }, - plugins: { - elasticsearch: { - getCluster: () => { - return { - callWithInternalUser: {}, - }; - }, - }, - }, - }); - - const request = jest.fn().mockReturnValue({ - payload: { - close: true, - open: true, - start: true, - stop: true, - }, - }); - describe('Upsert UIReindex Option', () => { it('call saved objects internal repository with the correct info', async () => { - const serverMock = server(); - const incCounterSORepoFunc = serverMock.savedObjects.getSavedObjectsRepository() - .incrementCounter; - - await upsertUIReindexOption(serverMock, request()); + const internalRepo = savedObjectsRepositoryMock.create(); + await upsertUIReindexOption({ + close: true, + open: true, + start: true, + stop: true, + savedObjects: { createInternalRepository: () => internalRepo } as any, + }); - expect(incCounterSORepoFunc).toHaveBeenCalledTimes(4); - expect(incCounterSORepoFunc).toHaveBeenCalledWith( + expect(internalRepo.incrementCounter).toHaveBeenCalledTimes(4); + expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, `ui_reindex.close` ); - expect(incCounterSORepoFunc).toHaveBeenCalledWith( + expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, `ui_reindex.open` ); - expect(incCounterSORepoFunc).toHaveBeenCalledWith( + expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, `ui_reindex.start` ); - expect(incCounterSORepoFunc).toHaveBeenCalledWith( + expect(internalRepo.incrementCounter).toHaveBeenCalledWith( UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID, `ui_reindex.stop` diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.ts new file mode 100644 index 0000000000000..0aaaf63196d67 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/es_ui_reindex_apis.ts @@ -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 { SavedObjectsServiceStart } from 'src/core/server'; +import { + UIReindex, + UIReindexOption, + UPGRADE_ASSISTANT_DOC_ID, + UPGRADE_ASSISTANT_TYPE, +} from '../../../common/types'; + +interface IncrementUIReindexOptionDependencies { + uiReindexOptionCounter: UIReindexOption; + savedObjects: SavedObjectsServiceStart; +} + +async function incrementUIReindexOptionCounter({ + savedObjects, + uiReindexOptionCounter, +}: IncrementUIReindexOptionDependencies) { + const internalRepository = savedObjects.createInternalRepository(); + + await internalRepository.incrementCounter( + UPGRADE_ASSISTANT_TYPE, + UPGRADE_ASSISTANT_DOC_ID, + `ui_reindex.${uiReindexOptionCounter}` + ); +} + +type UpsertUIReindexOptionDepencies = UIReindex & { savedObjects: SavedObjectsServiceStart }; + +export async function upsertUIReindexOption({ + start, + close, + open, + stop, + savedObjects, +}: UpsertUIReindexOptionDepencies): Promise { + if (close) { + await incrementUIReindexOptionCounter({ savedObjects, uiReindexOptionCounter: 'close' }); + } + + if (open) { + await incrementUIReindexOptionCounter({ savedObjects, uiReindexOptionCounter: 'open' }); + } + + if (start) { + await incrementUIReindexOptionCounter({ savedObjects, uiReindexOptionCounter: 'start' }); + } + + if (stop) { + await incrementUIReindexOptionCounter({ savedObjects, uiReindexOptionCounter: 'stop' }); + } + + return { + close, + open, + start, + stop, + }; +} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/index.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/index.ts similarity index 100% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/index.ts rename to x-pack/plugins/upgrade_assistant/server/lib/telemetry/index.ts diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/usage_collector.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts similarity index 78% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/usage_collector.test.ts rename to x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts index 27a0eef0d16f6..a4833d9a3d7fe 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/usage_collector.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts @@ -3,8 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { registerUpgradeAssistantUsageCollector } from './usage_collector'; +import { IClusterClient } from 'src/core/server'; /** * Since these route callbacks are so thin, these serve simply as integration tests @@ -14,20 +15,31 @@ import { registerUpgradeAssistantUsageCollector } from './usage_collector'; describe('Upgrade Assistant Usage Collector', () => { let makeUsageCollectorStub: any; let registerStub: any; - let server: any; + let dependencies: any; let callClusterStub: any; let usageCollection: any; + let clusterClient: IClusterClient; beforeEach(() => { + clusterClient = elasticsearchServiceMock.createClusterClient(); + (clusterClient.callAsInternalUser as jest.Mock).mockResolvedValue({ + persistent: {}, + transient: { + logger: { + deprecation: 'WARN', + }, + }, + }); makeUsageCollectorStub = jest.fn(); registerStub = jest.fn(); usageCollection = { makeUsageCollector: makeUsageCollectorStub, registerCollector: registerStub, }; - server = jest.fn().mockReturnValue({ + dependencies = { + usageCollection, savedObjects: { - getSavedObjectsRepository: jest.fn().mockImplementation(() => { + createInternalRepository: jest.fn().mockImplementation(() => { return { get: () => { return { @@ -45,31 +57,26 @@ describe('Upgrade Assistant Usage Collector', () => { }; }), }, - }); - callClusterStub = jest.fn().mockResolvedValue({ - persistent: {}, - transient: { - logger: { - deprecation: 'WARN', - }, + elasticsearch: { + adminClient: clusterClient, }, - }); + }; }); describe('registerUpgradeAssistantUsageCollector', () => { it('should registerCollector', () => { - registerUpgradeAssistantUsageCollector(usageCollection, server()); + registerUpgradeAssistantUsageCollector(dependencies); expect(registerStub).toHaveBeenCalledTimes(1); }); it('should call makeUsageCollector with type = upgrade-assistant', () => { - registerUpgradeAssistantUsageCollector(usageCollection, server()); + registerUpgradeAssistantUsageCollector(dependencies); expect(makeUsageCollectorStub).toHaveBeenCalledTimes(1); expect(makeUsageCollectorStub.mock.calls[0][0].type).toBe('upgrade-assistant-telemetry'); }); it('fetchUpgradeAssistantMetrics should return correct info', async () => { - registerUpgradeAssistantUsageCollector(usageCollection, server()); + registerUpgradeAssistantUsageCollector(dependencies); const upgradeAssistantStats = await makeUsageCollectorStub.mock.calls[0][0].fetch( callClusterStub ); diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/usage_collector.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts similarity index 72% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/usage_collector.ts rename to x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts index 1d24d190fa9f2..79d6e53c64ec0 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/lib/telemetry/usage_collector.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts @@ -5,8 +5,12 @@ */ import { set } from 'lodash'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SavedObjectsRepository } from 'src/core/server/saved_objects/service/lib/repository'; +import { + APICaller, + ElasticsearchServiceSetup, + ISavedObjectsRepository, + SavedObjectsServiceStart, +} from 'src/core/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { UPGRADE_ASSISTANT_DOC_ID, @@ -14,12 +18,11 @@ import { UpgradeAssistantTelemetry, UpgradeAssistantTelemetrySavedObject, UpgradeAssistantTelemetrySavedObjectAttributes, -} from '../../../../common/types'; -import { ServerShim } from '../../types'; +} from '../../../common/types'; import { isDeprecationLoggingEnabled } from '../es_deprecation_logging_apis'; async function getSavedObjectAttributesFromRepo( - savedObjectsRepository: SavedObjectsRepository, + savedObjectsRepository: ISavedObjectsRepository, docType: string, docID: string ) { @@ -35,9 +38,9 @@ async function getSavedObjectAttributesFromRepo( } } -async function getDeprecationLoggingStatusValue(callCluster: any): Promise { +async function getDeprecationLoggingStatusValue(callAsCurrentUser: APICaller): Promise { try { - const loggerDeprecationCallResult = await callCluster('cluster.getSettings', { + const loggerDeprecationCallResult = await callAsCurrentUser('cluster.getSettings', { includeDefaults: true, }); @@ -48,17 +51,17 @@ async function getDeprecationLoggingStatusValue(callCluster: any): Promise { - const { getSavedObjectsRepository } = server.savedObjects; - const savedObjectsRepository = getSavedObjectsRepository(callCluster); + const savedObjectsRepository = savedObjects.createInternalRepository(); const upgradeAssistantSOAttributes = await getSavedObjectAttributesFromRepo( savedObjectsRepository, UPGRADE_ASSISTANT_TYPE, UPGRADE_ASSISTANT_DOC_ID ); - const deprecationLoggingStatusValue = await getDeprecationLoggingStatusValue(callCluster); + const callAsInternalUser = adminClient.callAsInternalUser.bind(adminClient); + const deprecationLoggingStatusValue = await getDeprecationLoggingStatusValue(callAsInternalUser); const getTelemetrySavedObject = ( upgradeAssistantTelemetrySavedObjectAttrs: UpgradeAssistantTelemetrySavedObjectAttributes | null @@ -103,14 +106,21 @@ export async function fetchUpgradeAssistantMetrics( }; } -export function registerUpgradeAssistantUsageCollector( - usageCollection: UsageCollectionSetup, - server: ServerShim -) { +interface Dependencies { + elasticsearch: ElasticsearchServiceSetup; + savedObjects: SavedObjectsServiceStart; + usageCollection: UsageCollectionSetup; +} + +export function registerUpgradeAssistantUsageCollector({ + elasticsearch, + usageCollection, + savedObjects, +}: Dependencies) { const upgradeAssistantUsageCollector = usageCollection.makeUsageCollector({ type: UPGRADE_ASSISTANT_TYPE, isReady: () => true, - fetch: async (callCluster: any) => fetchUpgradeAssistantMetrics(callCluster, server), + fetch: async () => fetchUpgradeAssistantMetrics(elasticsearch, savedObjects), }); usageCollection.registerCollector(upgradeAssistantUsageCollector); diff --git a/x-pack/plugins/upgrade_assistant/server/plugin.ts b/x-pack/plugins/upgrade_assistant/server/plugin.ts new file mode 100644 index 0000000000000..6ccd073a9e020 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/plugin.ts @@ -0,0 +1,125 @@ +/* + * 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 { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; + +import { + Plugin, + CoreSetup, + CoreStart, + PluginInitializerContext, + Logger, + ElasticsearchServiceSetup, + SavedObjectsClient, + SavedObjectsServiceStart, +} from '../../../../src/core/server'; + +import { CloudSetup } from '../../cloud/server'; +import { LicensingPluginSetup } from '../../licensing/server'; + +import { CredentialStore, credentialStoreFactory } from './lib/reindexing/credential_store'; +import { ReindexWorker } from './lib/reindexing'; +import { registerUpgradeAssistantUsageCollector } from './lib/telemetry'; +import { registerClusterCheckupRoutes } from './routes/cluster_checkup'; +import { registerDeprecationLoggingRoutes } from './routes/deprecation_logging'; +import { registerReindexIndicesRoutes, createReindexWorker } from './routes/reindex_indices'; +import { registerTelemetryRoutes } from './routes/telemetry'; +import { RouteDependencies } from './types'; + +interface PluginsSetup { + usageCollection: UsageCollectionSetup; + licensing: LicensingPluginSetup; + cloud?: CloudSetup; +} + +export class UpgradeAssistantServerPlugin implements Plugin { + private readonly logger: Logger; + private readonly credentialStore: CredentialStore; + + // Properties set at setup + private licensing?: LicensingPluginSetup; + private elasticSearchService?: ElasticsearchServiceSetup; + + // Properties set at start + private savedObjectsServiceStart?: SavedObjectsServiceStart; + private worker?: ReindexWorker; + + constructor({ logger }: PluginInitializerContext) { + this.logger = logger.get(); + this.credentialStore = credentialStoreFactory(); + } + + private getWorker() { + if (!this.worker) { + throw new Error('Worker unavailable'); + } + return this.worker; + } + + setup( + { http, elasticsearch, getStartServices, capabilities }: CoreSetup, + { usageCollection, cloud, licensing }: PluginsSetup + ) { + this.elasticSearchService = elasticsearch; + this.licensing = licensing; + + const router = http.createRouter(); + + const dependencies: RouteDependencies = { + cloud, + router, + credentialStore: this.credentialStore, + log: this.logger, + getSavedObjectsService: () => { + if (!this.savedObjectsServiceStart) { + throw new Error('Saved Objects Start service not available'); + } + return this.savedObjectsServiceStart; + }, + licensing, + }; + + registerClusterCheckupRoutes(dependencies); + registerDeprecationLoggingRoutes(dependencies); + registerReindexIndicesRoutes(dependencies, this.getWorker.bind(this)); + // Bootstrap the needed routes and the collector for the telemetry + registerTelemetryRoutes(dependencies); + + if (usageCollection) { + getStartServices().then(([{ savedObjects }]) => { + registerUpgradeAssistantUsageCollector({ elasticsearch, usageCollection, savedObjects }); + }); + } + } + + start({ savedObjects }: CoreStart) { + this.savedObjectsServiceStart = savedObjects; + + // The ReindexWorker uses a map of request headers that contain the authentication credentials + // for a given reindex. We cannot currently store these in an the .kibana index b/c we do not + // want to expose these credentials to any unauthenticated users. We also want to avoid any need + // to add a user for a special index just for upgrading. This in-memory cache allows us to + // process jobs without the browser staying on the page, but will require that jobs go into + // a paused state if no Kibana nodes have the required credentials. + + this.worker = createReindexWorker({ + credentialStore: this.credentialStore, + licensing: this.licensing!, + elasticsearchService: this.elasticSearchService!, + logger: this.logger, + savedObjects: new SavedObjectsClient( + this.savedObjectsServiceStart.createInternalRepository() + ), + }); + + this.worker.start(); + } + + stop(): void { + if (this.worker) { + this.worker.stop(); + } + } +} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/__mocks__/request.mock.ts b/x-pack/plugins/upgrade_assistant/server/routes/__mocks__/request.mock.ts similarity index 92% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/__mocks__/request.mock.ts rename to x-pack/plugins/upgrade_assistant/server/routes/__mocks__/request.mock.ts index d09a66dbb4326..fb68e188bb255 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/__mocks__/request.mock.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/__mocks__/request.mock.ts @@ -6,7 +6,7 @@ export const createRequestMock = (opts?: { headers?: any; params?: Record; - payload?: Record; + body?: Record; }) => { return Object.assign({ headers: {} }, opts || {}); }; diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/__mocks__/routes.mock.ts b/x-pack/plugins/upgrade_assistant/server/routes/__mocks__/routes.mock.ts similarity index 72% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/__mocks__/routes.mock.ts rename to x-pack/plugins/upgrade_assistant/server/routes/__mocks__/routes.mock.ts index 3769bc389123e..a8be171dccd98 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/__mocks__/routes.mock.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/__mocks__/routes.mock.ts @@ -3,7 +3,21 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { RequestHandler } from 'kibana/server'; +import { RequestHandler, RequestHandlerContext } from 'src/core/server'; +import { + elasticsearchServiceMock, + savedObjectsClientMock, +} from '../../../../../../src/core/server/mocks'; + +export const routeHandlerContextMock = ({ + core: { + elasticsearch: { + adminClient: elasticsearchServiceMock.createScopedClusterClient(), + dataClient: elasticsearchServiceMock.createScopedClusterClient(), + }, + savedObjects: { client: savedObjectsClientMock.create() }, + }, +} as unknown) as RequestHandlerContext; /** * Creates a very crude mock of the new platform router implementation. This enables use to test diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/cluster_checkup.test.ts b/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.test.ts similarity index 73% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/cluster_checkup.test.ts rename to x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.test.ts index 3fe2e1797182b..16f8001f8e1de 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/cluster_checkup.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { kibanaResponseFactory } from 'src/core/server'; -import { createMockRouter, MockRouter } from './__mocks__/routes.mock'; +import { createMockRouter, MockRouter, routeHandlerContextMock } from './__mocks__/routes.mock'; import { createRequestMock } from './__mocks__/request.mock'; jest.mock('../lib/es_version_precheck', () => ({ @@ -24,32 +24,22 @@ import { registerClusterCheckupRoutes } from './cluster_checkup'; * more thoroughly in the es_migration_apis test. */ describe('cluster checkup API', () => { - afterEach(() => jest.clearAllMocks()); - let mockRouter: MockRouter; - let serverShim: any; - let ctxMock: any; - let mockPluginsSetup: any; + let routeDependencies: any; beforeEach(() => { mockRouter = createMockRouter(); - mockPluginsSetup = { + routeDependencies = { cloud: { isCloudEnabled: true, }, - }; - ctxMock = { - core: {}, - }; - serverShim = { router: mockRouter, - plugins: { - elasticsearch: { - getCluster: () => ({ callWithRequest: jest.fn() } as any), - } as any, - }, }; - registerClusterCheckupRoutes(serverShim, mockPluginsSetup); + registerClusterCheckupRoutes(routeDependencies); + }); + + afterEach(() => { + jest.resetAllMocks(); }); describe('with cloud enabled', () => { @@ -62,11 +52,11 @@ describe('cluster checkup API', () => { nodes: [], }); - await serverShim.router.getHandler({ + await routeDependencies.router.getHandler({ method: 'get', pathPattern: '/api/upgrade_assistant/status', - })(ctxMock, createRequestMock(), kibanaResponseFactory); - expect(spy.mock.calls[0][2]).toBe(true); + })(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory); + expect(spy.mock.calls[0][1]).toBe(true); }); }); @@ -77,10 +67,10 @@ describe('cluster checkup API', () => { indices: [], nodes: [], }); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'get', pathPattern: '/api/upgrade_assistant/status', - })(ctxMock, createRequestMock(), kibanaResponseFactory); + })(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory); expect(resp.status).toEqual(200); expect(JSON.stringify(resp.payload)).toMatchInlineSnapshot( @@ -93,10 +83,10 @@ describe('cluster checkup API', () => { e.status = 403; MigrationApis.getUpgradeAssistantStatus.mockRejectedValue(e); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'get', pathPattern: '/api/upgrade_assistant/status', - })(ctxMock, createRequestMock(), kibanaResponseFactory); + })(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory); expect(resp.status).toEqual(403); }); @@ -104,10 +94,10 @@ describe('cluster checkup API', () => { it('returns an 500 error if it throws', async () => { MigrationApis.getUpgradeAssistantStatus.mockRejectedValue(new Error(`scary error!`)); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'get', pathPattern: '/api/upgrade_assistant/status', - })(ctxMock, createRequestMock(), kibanaResponseFactory); + })(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory); expect(resp.status).toEqual(500); }); diff --git a/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.ts b/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.ts new file mode 100644 index 0000000000000..22a121ab78683 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/routes/cluster_checkup.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { getUpgradeAssistantStatus } from '../lib/es_migration_apis'; +import { versionCheckHandlerWrapper } from '../lib/es_version_precheck'; +import { RouteDependencies } from '../types'; + +export function registerClusterCheckupRoutes({ cloud, router }: RouteDependencies) { + const isCloudEnabled = Boolean(cloud?.isCloudEnabled); + + router.get( + { + path: '/api/upgrade_assistant/status', + validate: false, + }, + versionCheckHandlerWrapper( + async ( + { + core: { + elasticsearch: { dataClient }, + }, + }, + request, + response + ) => { + try { + return response.ok({ + body: await getUpgradeAssistantStatus(dataClient, isCloudEnabled), + }); + } catch (e) { + if (e.status === 403) { + return response.forbidden(e.message); + } + + return response.internalError({ body: e }); + } + } + ) + ); +} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/deprecation_logging.test.ts b/x-pack/plugins/upgrade_assistant/server/routes/deprecation_logging.test.ts similarity index 56% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/deprecation_logging.test.ts rename to x-pack/plugins/upgrade_assistant/server/routes/deprecation_logging.test.ts index d663361956374..845a0238f7918 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/deprecation_logging.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/deprecation_logging.test.ts @@ -5,7 +5,7 @@ */ import { kibanaResponseFactory } from 'src/core/server'; -import { createMockRouter, MockRouter } from './__mocks__/routes.mock'; +import { createMockRouter, MockRouter, routeHandlerContextMock } from './__mocks__/routes.mock'; import { createRequestMock } from './__mocks__/request.mock'; jest.mock('../lib/es_version_precheck', () => ({ @@ -21,42 +21,42 @@ import { registerDeprecationLoggingRoutes } from './deprecation_logging'; */ describe('deprecation logging API', () => { let mockRouter: MockRouter; - let serverShim: any; - let callWithRequest: any; - const ctxMock: any = {}; + let routeDependencies: any; beforeEach(() => { mockRouter = createMockRouter(); - callWithRequest = jest.fn(); - serverShim = { + routeDependencies = { router: mockRouter, - plugins: { - elasticsearch: { - getCluster: () => ({ callWithRequest } as any), - } as any, - }, }; - registerDeprecationLoggingRoutes(serverShim); + registerDeprecationLoggingRoutes(routeDependencies); + }); + + afterEach(() => { + jest.resetAllMocks(); }); describe('GET /api/upgrade_assistant/deprecation_logging', () => { it('returns isEnabled', async () => { - callWithRequest.mockResolvedValue({ default: { logger: { deprecation: 'WARN' } } }); - const resp = await serverShim.router.getHandler({ + (routeHandlerContextMock.core.elasticsearch.dataClient + .callAsCurrentUser as jest.Mock).mockResolvedValue({ + default: { logger: { deprecation: 'WARN' } }, + }); + const resp = await routeDependencies.router.getHandler({ method: 'get', pathPattern: '/api/upgrade_assistant/deprecation_logging', - })(ctxMock, createRequestMock(), kibanaResponseFactory); + })(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory); expect(resp.status).toEqual(200); expect(resp.payload).toEqual({ isEnabled: true }); }); it('returns an error if it throws', async () => { - callWithRequest.mockRejectedValue(new Error(`scary error!`)); - const resp = await serverShim.router.getHandler({ + (routeHandlerContextMock.core.elasticsearch.dataClient + .callAsCurrentUser as jest.Mock).mockRejectedValue(new Error(`scary error!`)); + const resp = await routeDependencies.router.getHandler({ method: 'get', pathPattern: '/api/upgrade_assistant/deprecation_logging', - })(ctxMock, createRequestMock(), kibanaResponseFactory); + })(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory); expect(resp.status).toEqual(500); }); @@ -64,21 +64,25 @@ describe('deprecation logging API', () => { describe('PUT /api/upgrade_assistant/deprecation_logging', () => { it('returns isEnabled', async () => { - callWithRequest.mockResolvedValue({ default: { logger: { deprecation: 'ERROR' } } }); - const resp = await serverShim.router.getHandler({ + (routeHandlerContextMock.core.elasticsearch.dataClient + .callAsCurrentUser as jest.Mock).mockResolvedValue({ + default: { logger: { deprecation: 'ERROR' } }, + }); + const resp = await routeDependencies.router.getHandler({ method: 'get', pathPattern: '/api/upgrade_assistant/deprecation_logging', - })(ctxMock, createRequestMock(), kibanaResponseFactory); + })(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory); expect(resp.payload).toEqual({ isEnabled: false }); }); it('returns an error if it throws', async () => { - callWithRequest.mockRejectedValue(new Error(`scary error!`)); - const resp = await serverShim.router.getHandler({ + (routeHandlerContextMock.core.elasticsearch.dataClient + .callAsCurrentUser as jest.Mock).mockRejectedValue(new Error(`scary error!`)); + const resp = await routeDependencies.router.getHandler({ method: 'put', pathPattern: '/api/upgrade_assistant/deprecation_logging', - })(ctxMock, { body: { isEnabled: false } }, kibanaResponseFactory); + })(routeHandlerContextMock, { body: { isEnabled: false } }, kibanaResponseFactory); expect(resp.status).toEqual(500); }); diff --git a/x-pack/plugins/upgrade_assistant/server/routes/deprecation_logging.ts b/x-pack/plugins/upgrade_assistant/server/routes/deprecation_logging.ts new file mode 100644 index 0000000000000..739a789c95ce0 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/routes/deprecation_logging.ts @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; + +import { + getDeprecationLoggingStatus, + setDeprecationLogging, +} from '../lib/es_deprecation_logging_apis'; +import { versionCheckHandlerWrapper } from '../lib/es_version_precheck'; +import { RouteDependencies } from '../types'; + +export function registerDeprecationLoggingRoutes({ router }: RouteDependencies) { + router.get( + { + path: '/api/upgrade_assistant/deprecation_logging', + validate: false, + }, + versionCheckHandlerWrapper( + async ( + { + core: { + elasticsearch: { dataClient }, + }, + }, + request, + response + ) => { + try { + const result = await getDeprecationLoggingStatus(dataClient); + return response.ok({ body: result }); + } catch (e) { + return response.internalError({ body: e }); + } + } + ) + ); + + router.put( + { + path: '/api/upgrade_assistant/deprecation_logging', + validate: { + body: schema.object({ + isEnabled: schema.boolean(), + }), + }, + }, + versionCheckHandlerWrapper( + async ( + { + core: { + elasticsearch: { dataClient }, + }, + }, + request, + response + ) => { + try { + const { isEnabled } = request.body as { isEnabled: boolean }; + return response.ok({ + body: await setDeprecationLogging(dataClient, isEnabled), + }); + } catch (e) { + return response.internalError({ body: e }); + } + } + ) + ); +} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/reindex_indices.test.ts b/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.test.ts similarity index 80% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/reindex_indices.test.ts rename to x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.test.ts index d520324239656..695bb6304cfdf 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/reindex_indices.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.test.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { savedObjectsClientMock } from 'src/core/server/mocks'; import { kibanaResponseFactory } from 'src/core/server'; -import { createMockRouter, MockRouter } from './__mocks__/routes.mock'; +import { licensingMock } from '../../../licensing/server/mocks'; +import { createMockRouter, MockRouter, routeHandlerContextMock } from './__mocks__/routes.mock'; import { createRequestMock } from './__mocks__/request.mock'; const mockReindexService = { @@ -31,12 +31,7 @@ jest.mock('../lib/reindexing', () => { }; }); -import { - IndexGroup, - ReindexSavedObject, - ReindexStatus, - ReindexWarning, -} from '../../../common/types'; +import { IndexGroup, ReindexSavedObject, ReindexStatus, ReindexWarning } from '../../common/types'; import { credentialStoreFactory } from '../lib/reindexing/credential_store'; import { registerReindexIndicesRoutes } from './reindex_indices'; @@ -46,9 +41,8 @@ import { registerReindexIndicesRoutes } from './reindex_indices'; * more thoroughly in the es_migration_apis test. */ describe('reindex API', () => { - let serverShim: any; + let routeDependencies: any; let mockRouter: MockRouter; - let ctxMock: any; const credentialStore = credentialStoreFactory(); const worker = { @@ -57,24 +51,13 @@ describe('reindex API', () => { } as any; beforeEach(() => { - ctxMock = { - core: { - savedObjects: savedObjectsClientMock.create(), - }, - }; mockRouter = createMockRouter(); - serverShim = { + routeDependencies = { + credentialStore, router: mockRouter, - plugins: { - xpack_main: { - info: jest.fn(), - }, - elasticsearch: { - getCluster: () => ({ callWithRequest: jest.fn() } as any), - } as any, - }, + licensing: licensingMock.createSetup(), }; - registerReindexIndicesRoutes(serverShim, worker, credentialStore); + registerReindexIndicesRoutes(routeDependencies, () => worker); mockReindexService.hasRequiredPrivileges.mockResolvedValue(true); mockReindexService.detectReindexWarnings.mockReset(); @@ -92,7 +75,9 @@ describe('reindex API', () => { credentialStore.clear(); }); - afterEach(() => jest.clearAllMocks()); + afterEach(() => { + jest.resetAllMocks(); + }); describe('GET /api/upgrade_assistant/reindex/{indexName}', () => { it('returns the attributes of the reindex operation and reindex warnings', async () => { @@ -101,10 +86,14 @@ describe('reindex API', () => { }); mockReindexService.detectReindexWarnings.mockResolvedValueOnce([ReindexWarning.allField]); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'get', pathPattern: '/api/upgrade_assistant/reindex/{indexName}', - })(ctxMock, createRequestMock({ params: { indexName: 'wowIndex' } }), kibanaResponseFactory); + })( + routeHandlerContextMock, + createRequestMock({ params: { indexName: 'wowIndex' } }), + kibanaResponseFactory + ); // It called into the service correctly expect(mockReindexService.findReindexOperation).toHaveBeenCalledWith('wowIndex'); @@ -121,10 +110,14 @@ describe('reindex API', () => { mockReindexService.findReindexOperation.mockResolvedValueOnce(null); mockReindexService.detectReindexWarnings.mockResolvedValueOnce(null); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'get', pathPattern: '/api/upgrade_assistant/reindex/{indexName}', - })(ctxMock, createRequestMock({ params: { indexName: 'anIndex' } }), kibanaResponseFactory); + })( + routeHandlerContextMock, + createRequestMock({ params: { indexName: 'anIndex' } }), + kibanaResponseFactory + ); expect(resp.status).toEqual(200); const data = resp.payload; @@ -137,10 +130,14 @@ describe('reindex API', () => { mockReindexService.detectReindexWarnings.mockResolvedValueOnce([]); mockReindexService.getIndexGroup.mockReturnValue(IndexGroup.ml); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'get', pathPattern: '/api/upgrade_assistant/reindex/{indexName}', - })(ctxMock, createRequestMock({ params: { indexName: 'anIndex' } }), kibanaResponseFactory); + })( + routeHandlerContextMock, + createRequestMock({ params: { indexName: 'anIndex' } }), + kibanaResponseFactory + ); expect(resp.status).toEqual(200); const data = resp.payload; @@ -154,10 +151,14 @@ describe('reindex API', () => { attributes: { indexName: 'theIndex' }, }); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'post', pathPattern: '/api/upgrade_assistant/reindex/{indexName}', - })(ctxMock, createRequestMock({ params: { indexName: 'theIndex' } }), kibanaResponseFactory); + })( + routeHandlerContextMock, + createRequestMock({ params: { indexName: 'theIndex' } }), + kibanaResponseFactory + ); // It called create correctly expect(mockReindexService.createReindexOperation).toHaveBeenCalledWith('theIndex'); @@ -173,10 +174,14 @@ describe('reindex API', () => { attributes: { indexName: 'theIndex' }, }); - await serverShim.router.getHandler({ + await routeDependencies.router.getHandler({ method: 'post', pathPattern: '/api/upgrade_assistant/reindex/{indexName}', - })(ctxMock, createRequestMock({ params: { indexName: 'theIndex' } }), kibanaResponseFactory); + })( + routeHandlerContextMock, + createRequestMock({ params: { indexName: 'theIndex' } }), + kibanaResponseFactory + ); expect(worker.forceRefresh).toHaveBeenCalled(); }); @@ -187,11 +192,11 @@ describe('reindex API', () => { } as ReindexSavedObject; mockReindexService.createReindexOperation.mockResolvedValueOnce(reindexOp); - await serverShim.router.getHandler({ + await routeDependencies.router.getHandler({ method: 'post', pathPattern: '/api/upgrade_assistant/reindex/{indexName}', })( - ctxMock, + routeHandlerContextMock, createRequestMock({ headers: { 'kbn-auth-x': 'HERE!', @@ -212,11 +217,11 @@ describe('reindex API', () => { attributes: { indexName: 'theIndex', status: ReindexStatus.inProgress }, }); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'post', pathPattern: '/api/upgrade_assistant/reindex/{indexName}', })( - ctxMock, + routeHandlerContextMock, createRequestMock({ params: { indexName: 'theIndex' }, }), @@ -235,11 +240,11 @@ describe('reindex API', () => { it('returns a 403 if required privileges fails', async () => { mockReindexService.hasRequiredPrivileges.mockResolvedValueOnce(false); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'post', pathPattern: '/api/upgrade_assistant/reindex/{indexName}', })( - ctxMock, + routeHandlerContextMock, createRequestMock({ params: { indexName: 'theIndex' }, }), @@ -254,11 +259,11 @@ describe('reindex API', () => { it('returns a 501', async () => { mockReindexService.cancelReindexing.mockResolvedValueOnce({}); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'post', pathPattern: '/api/upgrade_assistant/reindex/{indexName}/cancel', })( - ctxMock, + routeHandlerContextMock, createRequestMock({ params: { indexName: 'cancelMe' }, }), diff --git a/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.ts b/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.ts new file mode 100644 index 0000000000000..a910145474061 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/routes/reindex_indices.ts @@ -0,0 +1,217 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; +import { Logger, ElasticsearchServiceSetup, SavedObjectsClient } from 'src/core/server'; +import { ReindexStatus } from '../../common/types'; +import { versionCheckHandlerWrapper } from '../lib/es_version_precheck'; +import { reindexServiceFactory, ReindexWorker } from '../lib/reindexing'; +import { CredentialStore } from '../lib/reindexing/credential_store'; +import { reindexActionsFactory } from '../lib/reindexing/reindex_actions'; +import { RouteDependencies } from '../types'; +import { LicensingPluginSetup } from '../../../licensing/server'; + +interface CreateReindexWorker { + logger: Logger; + elasticsearchService: ElasticsearchServiceSetup; + credentialStore: CredentialStore; + savedObjects: SavedObjectsClient; + licensing: LicensingPluginSetup; +} + +export function createReindexWorker({ + logger, + elasticsearchService, + credentialStore, + savedObjects, + licensing, +}: CreateReindexWorker) { + const { adminClient } = elasticsearchService; + return new ReindexWorker(savedObjects, credentialStore, adminClient, logger, licensing); +} + +export function registerReindexIndicesRoutes( + { credentialStore, router, licensing, log }: RouteDependencies, + getWorker: () => ReindexWorker +) { + const BASE_PATH = '/api/upgrade_assistant/reindex'; + + // Start reindex for an index + router.post( + { + path: `${BASE_PATH}/{indexName}`, + validate: { + params: schema.object({ + indexName: schema.string(), + }), + }, + }, + versionCheckHandlerWrapper( + async ( + { + core: { + savedObjects, + elasticsearch: { dataClient }, + }, + }, + request, + response + ) => { + const { indexName } = request.params as any; + const { client } = savedObjects; + const callAsCurrentUser = dataClient.callAsCurrentUser.bind(dataClient); + const reindexActions = reindexActionsFactory(client, callAsCurrentUser); + const reindexService = reindexServiceFactory( + callAsCurrentUser, + reindexActions, + log, + licensing + ); + + try { + if (!(await reindexService.hasRequiredPrivileges(indexName))) { + return response.forbidden({ + body: `You do not have adequate privileges to reindex this index.`, + }); + } + + const existingOp = await reindexService.findReindexOperation(indexName); + + // If the reindexOp already exists and it's paused, resume it. Otherwise create a new one. + const reindexOp = + existingOp && existingOp.attributes.status === ReindexStatus.paused + ? await reindexService.resumeReindexOperation(indexName) + : await reindexService.createReindexOperation(indexName); + + // Add users credentials for the worker to use + credentialStore.set(reindexOp, request.headers); + + // Kick the worker on this node to immediately pickup the new reindex operation. + getWorker().forceRefresh(); + + return response.ok({ body: reindexOp.attributes }); + } catch (e) { + return response.internalError({ body: e }); + } + } + ) + ); + + // Get status + router.get( + { + path: `${BASE_PATH}/{indexName}`, + validate: { + params: schema.object({ + indexName: schema.string(), + }), + }, + }, + versionCheckHandlerWrapper( + async ( + { + core: { + savedObjects, + elasticsearch: { dataClient }, + }, + }, + request, + response + ) => { + const { client } = savedObjects; + const { indexName } = request.params as any; + const callAsCurrentUser = dataClient.callAsCurrentUser.bind(dataClient); + const reindexActions = reindexActionsFactory(client, callAsCurrentUser); + const reindexService = reindexServiceFactory( + callAsCurrentUser, + reindexActions, + log, + licensing + ); + + try { + const hasRequiredPrivileges = await reindexService.hasRequiredPrivileges(indexName); + const reindexOp = await reindexService.findReindexOperation(indexName); + // If the user doesn't have privileges than querying for warnings is going to fail. + const warnings = hasRequiredPrivileges + ? await reindexService.detectReindexWarnings(indexName) + : []; + const indexGroup = reindexService.getIndexGroup(indexName); + + return response.ok({ + body: { + reindexOp: reindexOp ? reindexOp.attributes : null, + warnings, + indexGroup, + hasRequiredPrivileges, + }, + }); + } catch (e) { + if (!e.isBoom) { + return response.internalError({ body: e }); + } + return response.customError({ + body: { + message: e.message, + }, + statusCode: e.statusCode, + }); + } + } + ) + ); + + // Cancel reindex + router.post( + { + path: `${BASE_PATH}/{indexName}/cancel`, + validate: { + params: schema.object({ + indexName: schema.string(), + }), + }, + }, + versionCheckHandlerWrapper( + async ( + { + core: { + savedObjects, + elasticsearch: { dataClient }, + }, + }, + request, + response + ) => { + const { indexName } = request.params as any; + const { client } = savedObjects; + const callAsCurrentUser = dataClient.callAsCurrentUser.bind(dataClient); + const reindexActions = reindexActionsFactory(client, callAsCurrentUser); + const reindexService = reindexServiceFactory( + callAsCurrentUser, + reindexActions, + log, + licensing + ); + + try { + await reindexService.cancelReindexing(indexName); + + return response.ok({ body: { acknowledged: true } }); + } catch (e) { + if (!e.isBoom) { + return response.internalError({ body: e }); + } + return response.customError({ + body: { + message: e.message, + }, + statusCode: e.statusCode, + }); + } + } + ) + ); +} diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/telemetry.test.ts b/x-pack/plugins/upgrade_assistant/server/routes/telemetry.test.ts similarity index 79% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/telemetry.test.ts rename to x-pack/plugins/upgrade_assistant/server/routes/telemetry.test.ts index 582c75e3701b6..b2b8ccf1ca57a 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/telemetry.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/telemetry.test.ts @@ -5,7 +5,8 @@ */ import { kibanaResponseFactory } from 'src/core/server'; -import { createMockRouter, MockRouter } from './__mocks__/routes.mock'; +import { savedObjectsServiceMock } from 'src/core/server/saved_objects/saved_objects_service.mock'; +import { createMockRouter, MockRouter, routeHandlerContextMock } from './__mocks__/routes.mock'; import { createRequestMock } from './__mocks__/request.mock'; jest.mock('../lib/telemetry/es_ui_open_apis', () => ({ @@ -26,24 +27,15 @@ import { registerTelemetryRoutes } from './telemetry'; * more thoroughly in the lib/telemetry tests. */ describe('Upgrade Assistant Telemetry API', () => { - let serverShim: any; + let routeDependencies: any; let mockRouter: MockRouter; - let ctxMock: any; beforeEach(() => { - ctxMock = {}; mockRouter = createMockRouter(); - serverShim = { + routeDependencies = { + getSavedObjectsService: () => savedObjectsServiceMock.create(), router: mockRouter, - plugins: { - xpack_main: { - info: jest.fn(), - }, - elasticsearch: { - getCluster: () => ({ callWithRequest: jest.fn() } as any), - } as any, - }, }; - registerTelemetryRoutes(serverShim); + registerTelemetryRoutes(routeDependencies); }); afterEach(() => jest.clearAllMocks()); @@ -57,10 +49,14 @@ describe('Upgrade Assistant Telemetry API', () => { (upsertUIOpenOption as jest.Mock).mockResolvedValue(returnPayload); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'put', pathPattern: '/api/upgrade_assistant/telemetry/ui_open', - })(ctxMock, createRequestMock(), kibanaResponseFactory); + })( + routeHandlerContextMock, + createRequestMock({ body: returnPayload }), + kibanaResponseFactory + ); expect(resp.payload).toEqual(returnPayload); }); @@ -74,13 +70,13 @@ describe('Upgrade Assistant Telemetry API', () => { (upsertUIOpenOption as jest.Mock).mockResolvedValue(returnPayload); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'put', pathPattern: '/api/upgrade_assistant/telemetry/ui_open', })( - ctxMock, + routeHandlerContextMock, createRequestMock({ - payload: { + body: { overview: true, cluster: true, indices: true, @@ -95,13 +91,13 @@ describe('Upgrade Assistant Telemetry API', () => { it('returns an error if it throws', async () => { (upsertUIOpenOption as jest.Mock).mockRejectedValue(new Error(`scary error!`)); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'put', pathPattern: '/api/upgrade_assistant/telemetry/ui_open', })( - ctxMock, + routeHandlerContextMock, createRequestMock({ - payload: { + body: { overview: false, }, }), @@ -123,13 +119,13 @@ describe('Upgrade Assistant Telemetry API', () => { (upsertUIReindexOption as jest.Mock).mockRejectedValue(returnPayload); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'put', pathPattern: '/api/upgrade_assistant/telemetry/ui_reindex', })( - ctxMock, + routeHandlerContextMock, createRequestMock({ - payload: { + body: { overview: false, }, }), @@ -149,13 +145,13 @@ describe('Upgrade Assistant Telemetry API', () => { (upsertUIReindexOption as jest.Mock).mockRejectedValue(returnPayload); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'put', pathPattern: '/api/upgrade_assistant/telemetry/ui_reindex', })( - ctxMock, + routeHandlerContextMock, createRequestMock({ - payload: { + body: { close: true, open: true, start: true, @@ -171,13 +167,13 @@ describe('Upgrade Assistant Telemetry API', () => { it('returns an error if it throws', async () => { (upsertUIReindexOption as jest.Mock).mockRejectedValue(new Error(`scary error!`)); - const resp = await serverShim.router.getHandler({ + const resp = await routeDependencies.router.getHandler({ method: 'put', pathPattern: '/api/upgrade_assistant/telemetry/ui_reindex', })( - ctxMock, + routeHandlerContextMock, createRequestMock({ - payload: { + body: { start: false, }, }), diff --git a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/telemetry.ts b/x-pack/plugins/upgrade_assistant/server/routes/telemetry.ts similarity index 66% rename from x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/telemetry.ts rename to x-pack/plugins/upgrade_assistant/server/routes/telemetry.ts index f08c49809033d..900a5e64c55c3 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/server/np_ready/routes/telemetry.ts +++ b/x-pack/plugins/upgrade_assistant/server/routes/telemetry.ts @@ -7,11 +7,10 @@ import { schema } from '@kbn/config-schema'; import { upsertUIOpenOption } from '../lib/telemetry/es_ui_open_apis'; import { upsertUIReindexOption } from '../lib/telemetry/es_ui_reindex_apis'; -import { ServerShimWithRouter } from '../types'; -import { createRequestShim } from './create_request_shim'; +import { RouteDependencies } from '../types'; -export function registerTelemetryRoutes(server: ServerShimWithRouter) { - server.router.put( +export function registerTelemetryRoutes({ router, getSavedObjectsService }: RouteDependencies) { + router.put( { path: '/api/upgrade_assistant/telemetry/ui_open', validate: { @@ -23,16 +22,23 @@ export function registerTelemetryRoutes(server: ServerShimWithRouter) { }, }, async (ctx, request, response) => { - const reqShim = createRequestShim(request); + const { cluster, indices, overview } = request.body; try { - return response.ok({ body: await upsertUIOpenOption(server, reqShim) }); + return response.ok({ + body: await upsertUIOpenOption({ + savedObjects: getSavedObjectsService(), + cluster, + indices, + overview, + }), + }); } catch (e) { return response.internalError({ body: e }); } } ); - server.router.put( + router.put( { path: '/api/upgrade_assistant/telemetry/ui_reindex', validate: { @@ -45,9 +51,17 @@ export function registerTelemetryRoutes(server: ServerShimWithRouter) { }, }, async (ctx, request, response) => { - const reqShim = createRequestShim(request); + const { close, open, start, stop } = request.body; try { - return response.ok({ body: await upsertUIReindexOption(server, reqShim) }); + return response.ok({ + body: await upsertUIReindexOption({ + savedObjects: getSavedObjectsService(), + close, + open, + start, + stop, + }), + }); } catch (e) { return response.internalError({ body: e }); } diff --git a/x-pack/plugins/upgrade_assistant/server/types.ts b/x-pack/plugins/upgrade_assistant/server/types.ts new file mode 100644 index 0000000000000..3f3beadd2f333 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/types.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IRouter, Logger, SavedObjectsServiceStart } from 'src/core/server'; +import { CloudSetup } from '../../cloud/server'; +import { CredentialStore } from './lib/reindexing/credential_store'; +import { LicensingPluginSetup } from '../../licensing/server'; + +export interface RouteDependencies { + router: IRouter; + credentialStore: CredentialStore; + log: Logger; + getSavedObjectsService: () => SavedObjectsServiceStart; + licensing: LicensingPluginSetup; + cloud?: CloudSetup; +} diff --git a/x-pack/test/upgrade_assistant_integration/upgrade_assistant/reindexing.js b/x-pack/test/upgrade_assistant_integration/upgrade_assistant/reindexing.js index 9fc8078162847..38fc1f0c6356f 100644 --- a/x-pack/test/upgrade_assistant_integration/upgrade_assistant/reindexing.js +++ b/x-pack/test/upgrade_assistant_integration/upgrade_assistant/reindexing.js @@ -6,10 +6,7 @@ import expect from '@kbn/expect'; -import { - ReindexStatus, - REINDEX_OP_TYPE, -} from '../../../legacy/plugins/upgrade_assistant/common/types'; +import { ReindexStatus, REINDEX_OP_TYPE } from '../../../plugins/upgrade_assistant/common/types'; export default function({ getService }) { const supertest = getService('supertest'); From 10bf90f9f57112c078db973b196974277404f745 Mon Sep 17 00:00:00 2001 From: "Devin W. Hurley" Date: Tue, 25 Feb 2020 09:34:53 -0500 Subject: [PATCH 056/123] [SIEM] [Detection Engine] Increase unit test coverage (#58274) * updates read privileges route tests * fixes test for 404 when alertsClient is not present, adds new test for catching errors at the route level for prepackaged rules route * fixes test for happy path on create rules bulk route (missing mock resulted in 200, but was still throwing an error), adds tests for covering case where a rule with a matching rule id is found to have already existed, adds a test covering the case where createRules throws an error and that error is caught in the catch block, and appears in the response * adds more jest functions to beforeEach to ensure mockImplementation state used by spyOn is not carried over between tests, increases test coverage for create rules route * updates unit test coverage for delete rules route and bulk delete * increase unit test coverage for find_rules_route * add test case to get_prepackaged_rules where findRules throws an error * adds unit test for missing alertsClient in patch_rules_bulk route * adds unit test coverage for transform error and pathRules throwing an error on patch rules route * adds unit test coverage for rule not found, transform error, and readRules throws an error on read_rules_route * adds unit test coverage for update rules (bulk) routes * increases unit test coverage for open close signals route * updates coverage for signals query route * adds unit tests for rules status route, updates utils test coverage. Removed unreachable code. * updates test coverage, removes usage of pipes from ndjson to stream conversion and returns arrays of tranformers to be used in createPromiseFromStreams so that unhandled promise rejections can be handled appropriately. * fixes type errors * fix bug on transform when rulestatus saved objects array is empty because we are no longer passing in the current status, we are passing in the whole saved object. * adds unit test for when readRules throws an error inside of get export by object ids * adds unit tests for catching errors on read rules and fixes property undefined bug in catch block * removes unused function from utils * adds the 'else' clause back to the getTupleDuplicateErrorsAndUniqueRules function and adds a test case for when an attempt to import rules with missing ruleIds is made, and the expected outcome. --- .../routes/__mocks__/request_responses.ts | 43 ++- .../routes/__mocks__/utils.ts | 37 ++ .../privileges/read_privileges_route.test.ts | 12 + .../rules/add_prepackaged_rules_route.test.ts | 23 +- .../rules/create_rules_bulk_route.test.ts | 49 ++- .../routes/rules/create_rules_route.test.ts | 48 ++- .../rules/delete_rules_bulk_route.test.ts | 10 + .../routes/rules/delete_rules_bulk_route.ts | 2 +- .../routes/rules/delete_rules_route.test.ts | 33 ++ .../routes/rules/find_rules_route.test.ts | 49 ++- .../rules/find_rules_status_route.test.ts | 96 +++++ .../routes/rules/find_rules_status_route.ts | 77 ++-- ...get_prepackaged_rules_status_route.test.ts | 17 + .../routes/rules/import_rules_route.test.ts | 38 +- .../routes/rules/import_rules_route.ts | 332 +++++++++--------- .../routes/rules/patch_rules_bulk.test.ts | 9 + .../routes/rules/patch_rules_route.test.ts | 34 ++ .../routes/rules/read_rules_route.test.ts | 41 ++- .../routes/rules/update_rules_bulk.test.ts | 4 +- .../routes/rules/update_rules_route.test.ts | 30 ++ .../routes/rules/utils.test.ts | 44 ++- .../detection_engine/routes/rules/utils.ts | 6 +- .../routes/signals/open_close_signals.test.ts | 14 + .../signals/open_close_signals_route.ts | 16 +- .../signals/query_signals_route.test.ts | 13 + .../routes/signals/query_signals_route.ts | 16 +- .../lib/detection_engine/routes/utils.test.ts | 12 + .../lib/detection_engine/routes/utils.ts | 9 + .../create_rules_stream_from_ndjson.test.ts | 64 +++- .../rules/create_rules_stream_from_ndjson.ts | 22 +- .../rules/get_export_by_object_ids.test.ts | 23 ++ .../detection_engine/rules/read_rules.test.ts | 73 ++++ .../lib/detection_engine/rules/read_rules.ts | 2 +- .../lib/detection_engine/rules/types.ts | 4 - .../security_and_spaces/tests/import_rules.ts | 11 + 35 files changed, 1038 insertions(+), 275 deletions(-) create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 1578c71dddc6a..2b50011cf4dff 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -427,13 +427,54 @@ export const getMockPrivileges = () => ({ has_encryption_key: true, }); -export const getFindResultStatus = (): SavedObjectsFindResponse => ({ +export const getFindResultStatusEmpty = (): SavedObjectsFindResponse => ({ page: 1, per_page: 1, total: 0, saved_objects: [], }); +export const getFindResultStatus = (): SavedObjectsFindResponse => ({ + page: 1, + per_page: 6, + total: 2, + saved_objects: [ + { + type: 'my-type', + id: 'e0b86950-4e9f-11ea-bdbd-07b56aa159b3', + attributes: { + alertId: '1ea5a820-4da1-4e82-92a1-2b43a7bece08', + statusDate: '2020-02-18T15:26:49.783Z', + status: 'succeeded', + lastFailureAt: null, + lastSuccessAt: '2020-02-18T15:26:49.783Z', + lastFailureMessage: null, + lastSuccessMessage: 'succeeded', + }, + references: [], + updated_at: '2020-02-18T15:26:51.333Z', + version: 'WzQ2LDFd', + }, + { + type: 'my-type', + id: '91246bd0-5261-11ea-9650-33b954270f67', + attributes: { + alertId: '1ea5a820-4da1-4e82-92a1-2b43a7bece08', + statusDate: '2020-02-18T15:15:58.806Z', + status: 'failed', + lastFailureAt: '2020-02-18T15:15:58.806Z', + lastSuccessAt: '2020-02-13T20:31:59.855Z', + lastFailureMessage: + 'Signal rule name: "Query with a rule id Number 1", id: "1ea5a820-4da1-4e82-92a1-2b43a7bece08", rule_id: "query-rule-id-1" has a time gap of 5 days (412682928ms), and could be missing signals within that time. Consider increasing your look behind time or adding more Kibana instances.', + lastSuccessMessage: 'succeeded', + }, + references: [], + updated_at: '2020-02-18T15:15:58.860Z', + version: 'WzMyLDFd', + }, + ], +}); + export const getIndexName = () => 'index-name'; export const getEmptyIndex = (): { _shards: Partial } => ({ _shards: { total: 0 }, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/utils.ts index f8c8e1f231ffa..32226e38a1f7f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/utils.ts @@ -26,6 +26,20 @@ export const getSimpleRule = (ruleId = 'rule-1'): Partial = query: 'user.name: root or user.name: admin', }); +/** + * This is a typical simple rule for testing that is easy for most basic testing + * @param ruleId + */ +export const getSimpleRuleWithId = (id = 'rule-1'): Partial => ({ + name: 'Simple Rule Query', + description: 'Simple Rule Query', + risk_score: 1, + id, + severity: 'high', + type: 'query', + query: 'user.name: root or user.name: admin', +}); + /** * Given an array of rule_id strings this will return a ndjson buffer which is useful * for testing uploads. @@ -51,3 +65,26 @@ export const getSimpleRuleAsMultipartContent = (ruleIds: string[], isNdjson = tr return Buffer.from(resultingPayload); }; + +/** + * Given an array of rule_id strings this will return a ndjson buffer which is useful + * for testing uploads. + * @param count Number of rules to generate + * @param isNdjson Boolean to determine file extension + */ +export const getSimpleRuleAsMultipartContentNoRuleId = (count: number, isNdjson = true): Buffer => { + const arrayOfRules = Array(count).fill(JSON.stringify(getSimpleRuleWithId())); + const stringOfRules = arrayOfRules.join('\r\n'); + + const resultingPayload = + `--${TEST_BOUNDARY}\r\n` + + `Content-Disposition: form-data; name="file"; filename="rules.${ + isNdjson ? 'ndjson' : 'json' + }\r\n` + + 'Content-Type: application/octet-stream\r\n' + + '\r\n' + + `${stringOfRules}\r\n` + + `--${TEST_BOUNDARY}--\r\n`; + + return Buffer.from(resultingPayload); +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.test.ts index 308ee95a77e20..3c31658c61d6e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.test.ts @@ -5,6 +5,7 @@ */ import { readPrivilegesRoute } from './read_privileges_route'; +import * as readPrivileges from '../../privileges/read_privileges'; import { createMockServer, createMockConfig, clientsServiceMock } from '../__mocks__'; import { getPrivilegeRequest, getMockPrivileges } from '../__mocks__/request_responses'; @@ -38,5 +39,16 @@ describe('read_privileges', () => { const { payload } = await inject(getPrivilegeRequest()); expect(JSON.parse(payload)).toEqual(getMockPrivileges()); }); + + test('returns 500 when bad response from readPrivileges', async () => { + jest.spyOn(readPrivileges, 'readPrivileges').mockImplementation(() => { + throw new Error('Test error'); + }); + const { payload } = await inject(getPrivilegeRequest()); + expect(JSON.parse(payload)).toEqual({ + message: 'Test error', + status_code: 500, + }); + }); }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts index e018ed4cc22ff..e6a93fdadcfca 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts @@ -6,7 +6,6 @@ import { omit } from 'lodash/fp'; -import { createRulesRoute } from './create_rules_route'; import { getFindResult, getResult, @@ -17,6 +16,7 @@ import { getNonEmptyIndex, } from '../__mocks__/request_responses'; import { createMockServer, createMockConfig, clientsServiceMock } from '../__mocks__'; +import * as updatePrepackagedRules from '../../rules/update_prepacked_rules'; jest.mock('../../rules/get_prepackaged_rules', () => { return { @@ -54,7 +54,8 @@ describe('add_prepackaged_rules_route', () => { beforeEach(() => { jest.resetAllMocks(); - + jest.restoreAllMocks(); + jest.clearAllMocks(); server = createMockServer(); config = createMockConfig(); getClients = clientsServiceMock.createGetScoped(); @@ -78,9 +79,7 @@ describe('add_prepackaged_rules_route', () => { test('returns 404 if alertClient is not available on the route', async () => { getClients.mockResolvedValue(omit('alertsClient', clients)); - const { inject, route } = createMockServer(); - createRulesRoute(route, config, getClients); - const { statusCode } = await inject(addPrepackagedRulesRequest()); + const { statusCode } = await server.inject(addPrepackagedRulesRequest()); expect(statusCode).toBe(404); }); }); @@ -126,5 +125,19 @@ describe('add_prepackaged_rules_route', () => { rules_updated: 1, }); }); + test('catches errors if payloads cause errors to be thrown', async () => { + jest.spyOn(updatePrepackagedRules, 'updatePrepackagedRules').mockImplementation(() => { + throw new Error('Test error'); + }); + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.actionsClient.create.mockResolvedValue(createActionResult()); + clients.alertsClient.create.mockResolvedValue(getResult()); + const { payload } = await server.inject(addPrepackagedRulesRequest()); + expect(JSON.parse(payload)).toEqual({ + message: 'Test error', + status_code: 500, + }); + }); }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts index 664d27a7572ad..931623ea6652c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts @@ -14,12 +14,15 @@ import { typicalPayload, getReadBulkRequest, getEmptyIndex, + getNonEmptyIndex, } from '../__mocks__/request_responses'; import { createMockServer, createMockConfig, clientsServiceMock } from '../__mocks__'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { createRulesBulkRoute } from './create_rules_bulk_route'; import { BulkError } from '../utils'; import { OutputRuleAlertRest } from '../../types'; +import * as createRules from '../../rules/create_rules'; +import * as readRules from '../../rules/read_rules'; describe('create_rules_bulk', () => { let server = createMockServer(); @@ -29,10 +32,14 @@ describe('create_rules_bulk', () => { beforeEach(() => { jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); server = createMockServer(); config = createMockConfig(); getClients = clientsServiceMock.createGetScoped(); clients = clientsServiceMock.createClients(); + clients.clusterClient.callAsCurrentUser.mockResolvedValue(getNonEmptyIndex()); + getClients.mockResolvedValue(clients); createRulesBulkRoute(server.route, config, getClients); @@ -44,8 +51,12 @@ describe('create_rules_bulk', () => { clients.alertsClient.get.mockResolvedValue(getResult()); clients.actionsClient.create.mockResolvedValue(createActionResult()); clients.alertsClient.create.mockResolvedValue(getResult()); - const { statusCode } = await server.inject(getReadBulkRequest()); + jest.spyOn(createRules, 'createRules').mockImplementation(async () => { + return getResult(); + }); + const { payload, statusCode } = await server.inject(getReadBulkRequest()); expect(statusCode).toBe(200); + expect(JSON.parse(payload).error).toBeUndefined(); }); test('returns 404 if alertClient is not available on the route', async () => { @@ -149,6 +160,24 @@ describe('create_rules_bulk', () => { expect(output.some(item => item.error?.status_code === 409)).toBeTruthy(); }); + test('returns 409 if duplicate rule_ids found in rule saved objects', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResult()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.actionsClient.create.mockResolvedValue(createActionResult()); + clients.alertsClient.create.mockResolvedValue(getResult()); + jest.spyOn(readRules, 'readRules').mockImplementation(async () => { + return getResult(); + }); + const request: ServerInjectOptions = { + method: 'POST', + url: `${DETECTION_ENGINE_RULES_URL}/_bulk_create`, + payload: [typicalPayload()], + }; + const { payload } = await server.inject(request); + const output: Array> = JSON.parse(payload); + expect(output.some(item => item.error?.status_code === 409)).toBeTruthy(); + }); + test('returns one error object in response when duplicate rule_ids found in request payload', async () => { clients.alertsClient.find.mockResolvedValue(getFindResult()); clients.alertsClient.get.mockResolvedValue(getResult()); @@ -163,4 +192,22 @@ describe('create_rules_bulk', () => { const output: Array> = JSON.parse(payload); expect(output.length).toBe(1); }); + + test('catches error if createRules throws error', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResult()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.actionsClient.create.mockResolvedValue(createActionResult()); + clients.alertsClient.create.mockResolvedValue(getResult()); + jest.spyOn(createRules, 'createRules').mockImplementation(async () => { + throw new Error('Test error'); + }); + const request: ServerInjectOptions = { + method: 'POST', + url: `${DETECTION_ENGINE_RULES_URL}/_bulk_create`, + payload: [typicalPayload()], + }; + const { payload } = await server.inject(request); + const output: Array> = JSON.parse(payload); + expect(output[0].error.message).toBe('Test error'); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.test.ts index 4f28771db8ed7..5ad43e70f2651 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.test.ts @@ -9,6 +9,9 @@ import { omit } from 'lodash/fp'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { createRulesRoute } from './create_rules_route'; +import * as createRules from '../../rules/create_rules'; +import * as readRules from '../../rules/read_rules'; +import * as utils from './utils'; import { getFindResult, @@ -29,8 +32,12 @@ describe('create_rules', () => { let clients = clientsServiceMock.createClients(); beforeEach(() => { + // jest carries state between mocked implementations when using + // spyOn. So now we're doing all three of these. + // https://github.com/facebook/jest/issues/7136#issuecomment-565976599 jest.resetAllMocks(); - + jest.restoreAllMocks(); + jest.clearAllMocks(); server = createMockServer(); config = createMockConfig(); getClients = clientsServiceMock.createGetScoped(); @@ -130,5 +137,44 @@ describe('create_rules', () => { const { statusCode } = await server.inject(request); expect(statusCode).toBe(400); }); + + test('catches error if createRules throws error', async () => { + clients.actionsClient.create.mockResolvedValue(createActionResult()); + clients.alertsClient.find.mockResolvedValue(getFindResult()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.alertsClient.create.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + jest.spyOn(createRules, 'createRules').mockImplementation(async () => { + throw new Error('Test error'); + }); + const { payload, statusCode } = await server.inject(getCreateRequest()); + expect(JSON.parse(payload).message).toBe('Test error'); + expect(statusCode).toBe(500); + }); + + test('catches error if transform returns null', async () => { + clients.actionsClient.create.mockResolvedValue(createActionResult()); + clients.alertsClient.find.mockResolvedValue(getFindResult()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.alertsClient.create.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + jest.spyOn(utils, 'transform').mockReturnValue(null); + const { payload, statusCode } = await server.inject(getCreateRequest()); + expect(JSON.parse(payload).message).toBe('Internal error transforming rules'); + expect(statusCode).toBe(500); + }); + + test('returns 409 if duplicate rule_ids found in rule saved objects', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResult()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.actionsClient.create.mockResolvedValue(createActionResult()); + clients.alertsClient.create.mockResolvedValue(getResult()); + jest.spyOn(readRules, 'readRules').mockImplementation(async () => { + return getResult(); + }); + const { payload } = await server.inject(getCreateRequest()); + const output = JSON.parse(payload); + expect(output.status_code).toEqual(409); + }); }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.test.ts index 855bf7f634c26..fb44f96d76859 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.test.ts @@ -48,6 +48,16 @@ describe('delete_rules', () => { expect(statusCode).toBe(200); }); + test('resturns 200 when deleting a single rule and related rule status', async () => { + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + clients.savedObjectsClient.delete.mockResolvedValue(true); + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.alertsClient.delete.mockResolvedValue({}); + const { statusCode } = await server.inject(getDeleteBulkRequest()); + expect(statusCode).toBe(200); + }); + test('returns 200 when deleting a single rule with a valid actionClient and alertClient by alertId using POST', async () => { clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); clients.alertsClient.get.mockResolvedValue(getResult()); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts index 6438318cb43db..aabf3e513bfea 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts @@ -58,7 +58,7 @@ export const createDeleteRulesBulkRoute = (getClients: GetScopedClients): Hapi.S ruleStatuses.saved_objects.forEach(async obj => savedObjectsClient.delete(ruleStatusSavedObjectType, obj.id) ); - return transformOrBulkError(idOrRuleIdOrUnknown, rule); + return transformOrBulkError(idOrRuleIdOrUnknown, rule, ruleStatuses); } else { return getIdBulkError({ id, ruleId }); } diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts index a0a6f61223279..57c7c85976619 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts @@ -7,6 +7,8 @@ import { ServerInjectOptions } from 'hapi'; import { omit } from 'lodash/fp'; import { deleteRulesRoute } from './delete_rules_route'; +import * as utils from './utils'; +import * as deleteRules from '../../rules/delete_rules'; import { getFindResult, @@ -25,7 +27,12 @@ describe('delete_rules', () => { let clients = clientsServiceMock.createClients(); beforeEach(() => { + // jest carries state between mocked implementations when using + // spyOn. So now we're doing all three of these. + // https://github.com/facebook/jest/issues/7136#issuecomment-565976599 jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); server = createMockServer(); getClients = clientsServiceMock.createGetScoped(); clients = clientsServiceMock.createClients(); @@ -73,6 +80,32 @@ describe('delete_rules', () => { const { statusCode } = await inject(getDeleteRequest()); expect(statusCode).toBe(404); }); + + test('returns 500 when transform fails', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.alertsClient.delete.mockResolvedValue({}); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + clients.savedObjectsClient.delete.mockResolvedValue({}); + jest.spyOn(utils, 'transform').mockReturnValue(null); + const { payload, statusCode } = await server.inject(getDeleteRequest()); + expect(JSON.parse(payload).message).toBe('Internal error transforming rules'); + expect(statusCode).toBe(500); + }); + + test('catches error if deleteRules throws error', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.alertsClient.delete.mockResolvedValue({}); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + clients.savedObjectsClient.delete.mockResolvedValue({}); + jest.spyOn(deleteRules, 'deleteRules').mockImplementation(async () => { + throw new Error('Test error'); + }); + const { payload, statusCode } = await server.inject(getDeleteRequestById()); + expect(JSON.parse(payload).message).toBe('Test error'); + expect(statusCode).toBe(500); + }); }); describe('validation', () => { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_route.test.ts index 5b75f17164acf..019424ea2420a 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_route.test.ts @@ -6,13 +6,22 @@ import { omit } from 'lodash/fp'; +import { + getFindResult, + getResult, + getFindResultWithSingleHit, + getFindResultStatus, + getFindRequest, +} from '../__mocks__/request_responses'; import { createMockServer } from '../__mocks__'; import { clientsServiceMock } from '../__mocks__/clients_service_mock'; +import * as utils from './utils'; +import * as findRules from '../../rules/find_rules'; + import { findRulesRoute } from './find_rules_route'; import { ServerInjectOptions } from 'hapi'; -import { getFindResult, getResult, getFindRequest } from '../__mocks__/request_responses'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; describe('find_rules', () => { @@ -21,7 +30,12 @@ describe('find_rules', () => { let clients = clientsServiceMock.createClients(); beforeEach(() => { + // jest carries state between mocked implementations when using + // spyOn. So now we're doing all three of these. + // https://github.com/facebook/jest/issues/7136#issuecomment-565976599 jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); server = createMockServer(); getClients = clientsServiceMock.createGetScoped(); @@ -33,15 +47,10 @@ describe('find_rules', () => { }); describe('status codes with actionClient and alertClient', () => { - test('returns 200 when finding a single rule with a valid actionClient and alertClient', async () => { - clients.alertsClient.find.mockResolvedValue(getFindResult()); - clients.actionsClient.find.mockResolvedValue({ - page: 1, - perPage: 1, - total: 0, - data: [], - }); + test('returns 200 when finding a single rule with a valid alertsClient', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); clients.alertsClient.get.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); const { statusCode } = await server.inject(getFindRequest()); expect(statusCode).toBe(200); }); @@ -53,6 +62,28 @@ describe('find_rules', () => { const { statusCode } = await inject(getFindRequest()); expect(statusCode).toBe(404); }); + + test('catches error when transformation fails', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + jest.spyOn(utils, 'transformFindAlerts').mockReturnValue(null); + const { payload, statusCode } = await server.inject(getFindRequest()); + expect(statusCode).toBe(500); + expect(JSON.parse(payload).message).toBe('unknown data type, error transforming alert'); + }); + + test('catch error when findRules function throws error', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + jest.spyOn(findRules, 'findRules').mockImplementation(async () => { + throw new Error('Test error'); + }); + const { payload, statusCode } = await server.inject(getFindRequest()); + expect(JSON.parse(payload).message).toBe('Test error'); + expect(statusCode).toBe(500); + }); }); describe('validation', () => { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts new file mode 100644 index 0000000000000..00411c550fa2e --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts @@ -0,0 +1,96 @@ +/* + * 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 { omit } from 'lodash/fp'; + +import { getFindResultStatus } from '../__mocks__/request_responses'; +import { createMockServer } from '../__mocks__'; +import { clientsServiceMock } from '../__mocks__/clients_service_mock'; + +import { findRulesStatusesRoute } from './find_rules_status_route'; +import { ServerInjectOptions } from 'hapi'; + +import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; + +describe('find_statuses', () => { + let server = createMockServer(); + let getClients = clientsServiceMock.createGetScoped(); + let clients = clientsServiceMock.createClients(); + + beforeEach(() => { + // jest carries state between mocked implementations when using + // spyOn. So now we're doing all three of these. + // https://github.com/facebook/jest/issues/7136#issuecomment-565976599 + jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); + + server = createMockServer(); + getClients = clientsServiceMock.createGetScoped(); + clients = clientsServiceMock.createClients(); + + getClients.mockResolvedValue(clients); + + findRulesStatusesRoute(server.route, getClients); + }); + + describe('status codes with actionClient and alertClient', () => { + test('returns 200 when finding a single rule status with a valid alertsClient', async () => { + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + const request: ServerInjectOptions = { + method: 'GET', + url: `${DETECTION_ENGINE_RULES_URL}/_find_statuses?ids=["someid"]`, + }; + const { statusCode } = await server.inject(request); + expect(statusCode).toBe(200); + }); + + test('returns 404 if alertClient is not available on the route', async () => { + getClients.mockResolvedValue(omit('alertsClient', clients)); + const request: ServerInjectOptions = { + method: 'GET', + url: `${DETECTION_ENGINE_RULES_URL}/_find_statuses?ids=["someid"]`, + }; + const { statusCode } = await server.inject(request); + expect(statusCode).toBe(404); + }); + + test('catch error when savedObjectsClient find function throws error', async () => { + clients.savedObjectsClient.find.mockImplementation(async () => { + throw new Error('Test error'); + }); + const request: ServerInjectOptions = { + method: 'GET', + url: `${DETECTION_ENGINE_RULES_URL}/_find_statuses?ids=["someid"]`, + }; + const { payload, statusCode } = await server.inject(request); + expect(JSON.parse(payload).message).toBe('Test error'); + expect(statusCode).toBe(500); + }); + }); + + describe('validation', () => { + test('returns 400 if id is given instead of ids', async () => { + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + const request: ServerInjectOptions = { + method: 'GET', + url: `${DETECTION_ENGINE_RULES_URL}/_find_statuses?id=["someid"]`, + }; + const { statusCode } = await server.inject(request); + expect(statusCode).toBe(400); + }); + + test('returns 200 if the set of optional query parameters are given', async () => { + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + const request: ServerInjectOptions = { + method: 'GET', + url: `${DETECTION_ENGINE_RULES_URL}/_find_statuses?ids=["someid"]`, + }; + const { statusCode } = await server.inject(request); + expect(statusCode).toBe(200); + }); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.ts index fe8742ff0b60c..c496c7b7ce59c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.ts @@ -5,7 +5,6 @@ */ import Hapi from 'hapi'; -import { snakeCase } from 'lodash/fp'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { LegacyServices, LegacyRequest } from '../../../../types'; @@ -18,17 +17,7 @@ import { IRuleStatusAttributes, } from '../../rules/types'; import { ruleStatusSavedObjectType } from '../../rules/saved_object_mappings'; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const convertToSnakeCase = >(obj: T): Partial | null => { - if (!obj) { - return null; - } - return Object.keys(obj).reduce((acc, item) => { - const newKey = snakeCase(item); - return { ...acc, [newKey]: obj[item] }; - }, {}); -}; +import { transformError, convertToSnakeCase } from '../utils'; export const createFindRulesStatusRoute = (getClients: GetScopedClients): Hapi.ServerRoute => ({ method: 'GET', @@ -57,33 +46,43 @@ export const createFindRulesStatusRoute = (getClients: GetScopedClients): Hapi.S "anotherAlertId": ... } */ - const statuses = await query.ids.reduce>(async (acc, id) => { - const lastFiveErrorsForId = await savedObjectsClient.find< - IRuleSavedAttributesSavedObjectAttributes - >({ - type: ruleStatusSavedObjectType, - perPage: 6, - sortField: 'statusDate', - sortOrder: 'desc', - search: id, - searchFields: ['alertId'], - }); - const accumulated = await acc; - const currentStatus = convertToSnakeCase( - lastFiveErrorsForId.saved_objects[0]?.attributes - ); - const failures = lastFiveErrorsForId.saved_objects - .slice(1) - .map(errorItem => convertToSnakeCase(errorItem.attributes)); - return { - ...accumulated, - [id]: { - current_status: currentStatus, - failures, - }, - }; - }, Promise.resolve({})); - return statuses; + try { + const statuses = await query.ids.reduce>(async (acc, id) => { + const lastFiveErrorsForId = await savedObjectsClient.find< + IRuleSavedAttributesSavedObjectAttributes + >({ + type: ruleStatusSavedObjectType, + perPage: 6, + sortField: 'statusDate', + sortOrder: 'desc', + search: id, + searchFields: ['alertId'], + }); + const accumulated = await acc; + const currentStatus = convertToSnakeCase( + lastFiveErrorsForId.saved_objects[0]?.attributes + ); + const failures = lastFiveErrorsForId.saved_objects + .slice(1) + .map(errorItem => convertToSnakeCase(errorItem.attributes)); + return { + ...accumulated, + [id]: { + current_status: currentStatus, + failures, + }, + }; + }, Promise.resolve({})); + return statuses; + } catch (err) { + const error = transformError(err); + return headers + .response({ + message: error.message, + status_code: error.statusCode, + }) + .code(error.statusCode); + } }, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts index 8f27910a7e5e2..99157b4d15360 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts @@ -7,6 +7,7 @@ import { omit } from 'lodash/fp'; import { getPrepackagedRulesStatusRoute } from './get_prepackaged_rules_status_route'; +import * as findRules from '../../rules/find_rules'; import { getFindResult, @@ -47,7 +48,12 @@ describe('get_prepackaged_rule_status_route', () => { let clients = clientsServiceMock.createClients(); beforeEach(() => { + // jest carries state between mocked implementations when using + // spyOn. So now we're doing all three of these. + // https://github.com/facebook/jest/issues/7136#issuecomment-565976599 jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); server = createMockServer(); getClients = clientsServiceMock.createGetScoped(); @@ -76,6 +82,17 @@ describe('get_prepackaged_rule_status_route', () => { const { statusCode } = await inject(getPrepackagedRulesStatusRequest()); expect(statusCode).toBe(404); }); + + test('catch error when findRules function throws error', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + jest.spyOn(findRules, 'findRules').mockImplementation(async () => { + throw new Error('Test error'); + }); + const { payload, statusCode } = await server.inject(getPrepackagedRulesStatusRequest()); + expect(JSON.parse(payload).message).toBe('Test error'); + expect(statusCode).toBe(500); + }); }); describe('payload', () => { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.test.ts index b1dd08f8ca371..c8b77e505b5d7 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.test.ts @@ -8,6 +8,7 @@ import { omit } from 'lodash/fp'; import { getSimpleRuleAsMultipartContent, + getSimpleRuleAsMultipartContentNoRuleId, TEST_BOUNDARY, UNPARSABLE_LINE, getSimpleRule, @@ -25,6 +26,7 @@ import { import { createMockServer, createMockConfig, clientsServiceMock } from '../__mocks__'; import { importRulesRoute } from './import_rules_route'; import { DEFAULT_SIGNALS_INDEX } from '../../../../../common/constants'; +import * as createRulesStreamFromNdJson from '../../rules/create_rules_stream_from_ndjson'; describe('import_rules_route', () => { let server = createMockServer(); @@ -33,8 +35,12 @@ describe('import_rules_route', () => { let clients = clientsServiceMock.createClients(); beforeEach(() => { + // jest carries state between mocked implementations when using + // spyOn. So now we're doing all three of these. + // https://github.com/facebook/jest/issues/7136#issuecomment-565976599 jest.resetAllMocks(); - + jest.restoreAllMocks(); + jest.clearAllMocks(); server = createMockServer(); config = createMockConfig(); config = () => ({ @@ -94,6 +100,21 @@ describe('import_rules_route', () => { const { statusCode } = await inject(getImportRulesRequest(requestPayload)); expect(statusCode).toEqual(404); }); + + test('returns error if createPromiseFromStreams throws error', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResult()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.alertsClient.create.mockResolvedValue(getResult()); + jest + .spyOn(createRulesStreamFromNdJson, 'createRulesStreamFromNdJson') + .mockImplementation(() => { + throw new Error('Test error'); + }); + const requestPayload = getSimpleRuleAsMultipartContent(['rule-1']); + const { payload, statusCode } = await server.inject(getImportRulesRequest(requestPayload)); + expect(JSON.parse(payload).message).toBe('Test error'); + expect(statusCode).toBe(500); + }); }); describe('validation', () => { @@ -306,6 +327,21 @@ describe('import_rules_route', () => { expect(statusCode).toEqual(200); }); + test('returns 200 with errors if all rules are missing rule_ids and import fails on validation', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResult()); + + const requestPayload = getSimpleRuleAsMultipartContentNoRuleId(2); + const { statusCode, payload } = await server.inject(getImportRulesRequest(requestPayload)); + const parsed: ImportSuccessError = JSON.parse(payload); + + expect(parsed.success).toEqual(false); + expect(parsed.errors[0].error.message).toEqual( + 'child "rule_id" fails because ["rule_id" is required]' + ); + expect(parsed.errors[0].error.status_code).toEqual(400); + expect(statusCode).toEqual(200); + }); + test('returns 200 with reported conflict if error parsing rule', async () => { const multipartPayload = `--${TEST_BOUNDARY}\r\n` + diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts index f438e0120f96a..a9358a47f25fc 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts @@ -7,6 +7,7 @@ import Hapi from 'hapi'; import { chunk, isEmpty } from 'lodash/fp'; import { extname } from 'path'; +import { Readable } from 'stream'; import { createPromiseFromStreams } from '../../../../../../../../../src/legacy/utils/streams'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; @@ -15,7 +16,7 @@ import { createRules } from '../../rules/create_rules'; import { ImportRulesRequest } from '../../rules/types'; import { readRules } from '../../rules/read_rules'; import { getIndexExists } from '../../index/get_index_exists'; -import { getIndex, createBulkErrorObject, ImportRuleResponse } from '../utils'; +import { getIndex, transformError, createBulkErrorObject, ImportRuleResponse } from '../utils'; import { createRulesStreamFromNdJson } from '../../rules/create_rules_stream_from_ndjson'; import { ImportRuleAlertRest } from '../../types'; import { patchRules } from '../../rules/patch_rules'; @@ -74,179 +75,192 @@ export const createImportRulesRoute = ( } const objectLimit = config().get('savedObjects.maxImportExportSize'); - const readStream = createRulesStreamFromNdJson(request.payload.file, objectLimit); - const parsedObjects = await createPromiseFromStreams([readStream]); - const [duplicateIdErrors, uniqueParsedObjects] = getTupleDuplicateErrorsAndUniqueRules( - parsedObjects, - request.query.overwrite - ); + try { + const readStream = createRulesStreamFromNdJson(objectLimit); + const parsedObjects = await createPromiseFromStreams([ + request.payload.file as Readable, + ...readStream, + ]); + const [duplicateIdErrors, uniqueParsedObjects] = getTupleDuplicateErrorsAndUniqueRules( + parsedObjects, + request.query.overwrite + ); - const chunkParseObjects = chunk(CHUNK_PARSED_OBJECT_SIZE, uniqueParsedObjects); - let importRuleResponse: ImportRuleResponse[] = []; + const chunkParseObjects = chunk(CHUNK_PARSED_OBJECT_SIZE, uniqueParsedObjects); + let importRuleResponse: ImportRuleResponse[] = []; - while (chunkParseObjects.length) { - const batchParseObjects = chunkParseObjects.shift() ?? []; - const newImportRuleResponse = await Promise.all( - batchParseObjects.reduce>>((accum, parsedRule) => { - const importsWorkerPromise = new Promise( - async (resolve, reject) => { - if (parsedRule instanceof Error) { - // If the JSON object had a validation or parse error then we return - // early with the error and an (unknown) for the ruleId - resolve( - createBulkErrorObject({ - statusCode: 400, - message: parsedRule.message, - }) - ); - return null; - } - const { - description, - enabled, - false_positives: falsePositives, - from, - immutable, - query, - language, - output_index: outputIndex, - saved_id: savedId, - meta, - filters, - rule_id: ruleId, - index, - interval, - max_signals: maxSignals, - risk_score: riskScore, - name, - severity, - tags, - threat, - to, - type, - references, - timeline_id: timelineId, - timeline_title: timelineTitle, - version, - } = parsedRule; - try { - const finalIndex = getIndex(spacesClient.getSpaceId, config); - const indexExists = await getIndexExists( - clusterClient.callAsCurrentUser, - finalIndex - ); - if (!indexExists) { + while (chunkParseObjects.length) { + const batchParseObjects = chunkParseObjects.shift() ?? []; + const newImportRuleResponse = await Promise.all( + batchParseObjects.reduce>>((accum, parsedRule) => { + const importsWorkerPromise = new Promise( + async (resolve, reject) => { + if (parsedRule instanceof Error) { + // If the JSON object had a validation or parse error then we return + // early with the error and an (unknown) for the ruleId resolve( createBulkErrorObject({ - ruleId, - statusCode: 409, - message: `To create a rule, the index must exist first. Index ${finalIndex} does not exist`, + statusCode: 400, + message: parsedRule.message, }) ); + return null; } - const rule = await readRules({ alertsClient, ruleId }); - if (rule == null) { - await createRules({ - alertsClient, - actionsClient, - description, - enabled, - falsePositives, - from, - immutable, - query, - language, - outputIndex: finalIndex, - savedId, - timelineId, - timelineTitle, - meta, - filters, - ruleId, - index, - interval, - maxSignals, - riskScore, - name, - severity, - tags, - to, - type, - threat, - references, - version, - }); - resolve({ rule_id: ruleId, status_code: 200 }); - } else if (rule != null && request.query.overwrite) { - await patchRules({ - alertsClient, - actionsClient, - savedObjectsClient, - description, - enabled, - falsePositives, - from, - immutable, - query, - language, - outputIndex, - savedId, - timelineId, - timelineTitle, - meta, - filters, - id: undefined, - ruleId, - index, - interval, - maxSignals, - riskScore, - name, - severity, - tags, - to, - type, - threat, - references, - version, - }); - resolve({ rule_id: ruleId, status_code: 200 }); - } else if (rule != null) { + const { + description, + enabled, + false_positives: falsePositives, + from, + immutable, + query, + language, + output_index: outputIndex, + saved_id: savedId, + meta, + filters, + rule_id: ruleId, + index, + interval, + max_signals: maxSignals, + risk_score: riskScore, + name, + severity, + tags, + threat, + to, + type, + references, + timeline_id: timelineId, + timeline_title: timelineTitle, + version, + } = parsedRule; + try { + const finalIndex = getIndex(spacesClient.getSpaceId, config); + const indexExists = await getIndexExists( + clusterClient.callAsCurrentUser, + finalIndex + ); + if (!indexExists) { + resolve( + createBulkErrorObject({ + ruleId, + statusCode: 409, + message: `To create a rule, the index must exist first. Index ${finalIndex} does not exist`, + }) + ); + } + const rule = await readRules({ alertsClient, ruleId }); + if (rule == null) { + await createRules({ + alertsClient, + actionsClient, + description, + enabled, + falsePositives, + from, + immutable, + query, + language, + outputIndex: finalIndex, + savedId, + timelineId, + timelineTitle, + meta, + filters, + ruleId, + index, + interval, + maxSignals, + riskScore, + name, + severity, + tags, + to, + type, + threat, + references, + version, + }); + resolve({ rule_id: ruleId, status_code: 200 }); + } else if (rule != null && request.query.overwrite) { + await patchRules({ + alertsClient, + actionsClient, + savedObjectsClient, + description, + enabled, + falsePositives, + from, + immutable, + query, + language, + outputIndex, + savedId, + timelineId, + timelineTitle, + meta, + filters, + id: undefined, + ruleId, + index, + interval, + maxSignals, + riskScore, + name, + severity, + tags, + to, + type, + threat, + references, + version, + }); + resolve({ rule_id: ruleId, status_code: 200 }); + } else if (rule != null) { + resolve( + createBulkErrorObject({ + ruleId, + statusCode: 409, + message: `rule_id: "${ruleId}" already exists`, + }) + ); + } + } catch (err) { resolve( createBulkErrorObject({ ruleId, - statusCode: 409, - message: `rule_id: "${ruleId}" already exists`, + statusCode: 400, + message: err.message, }) ); } - } catch (err) { - resolve( - createBulkErrorObject({ - ruleId, - statusCode: 400, - message: err.message, - }) - ); } - } - ); - return [...accum, importsWorkerPromise]; - }, []) - ); - importRuleResponse = [ - ...duplicateIdErrors, - ...importRuleResponse, - ...newImportRuleResponse, - ]; - } + ); + return [...accum, importsWorkerPromise]; + }, []) + ); + importRuleResponse = [ + ...duplicateIdErrors, + ...importRuleResponse, + ...newImportRuleResponse, + ]; + } - const errorsResp = importRuleResponse.filter(resp => !isEmpty(resp.error)); - return { - success: errorsResp.length === 0, - success_count: importRuleResponse.filter(resp => resp.status_code === 200).length, - errors: errorsResp, - }; + const errorsResp = importRuleResponse.filter(resp => !isEmpty(resp.error)); + return { + success: errorsResp.length === 0, + success_count: importRuleResponse.filter(resp => resp.status_code === 200).length, + errors: errorsResp, + }; + } catch (exc) { + const error = transformError(exc); + return headers + .response({ + message: error.message, + status_code: error.statusCode, + }) + .code(error.statusCode); + } }, }; }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk.test.ts index 02af4135b534f..1cfb4ae81ab85 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk.test.ts @@ -15,6 +15,7 @@ import { typicalPayload, getFindResultWithSingleHit, getPatchBulkRequest, + getFindResultStatus, } from '../__mocks__/request_responses'; import { createMockServer, clientsServiceMock } from '../__mocks__'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; @@ -43,6 +44,7 @@ describe('patch_rules_bulk', () => { clients.alertsClient.get.mockResolvedValue(getResult()); clients.actionsClient.update.mockResolvedValue(updateActionResult()); clients.alertsClient.update.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); const { statusCode } = await server.inject(getPatchBulkRequest()); expect(statusCode).toBe(200); }); @@ -56,6 +58,13 @@ describe('patch_rules_bulk', () => { expect(statusCode).toBe(200); }); + test('returns 404 as a response when missing alertsClient', async () => { + getClients.mockResolvedValue(omit('alertsClient', clients)); + clients.actionsClient.update.mockResolvedValue(updateActionResult()); + const { statusCode } = await server.inject(getPatchBulkRequest()); + expect(statusCode).toBe(404); + }); + test('returns 404 within the payload when updating a single rule that does not exist', async () => { clients.alertsClient.find.mockResolvedValue(getFindResult()); clients.alertsClient.get.mockResolvedValue(getResult()); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts index cc84b08fdef11..04cd3a026562f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts @@ -7,6 +7,8 @@ import { ServerInjectOptions } from 'hapi'; import { omit } from 'lodash/fp'; import { patchRulesRoute } from './patch_rules_route'; +import * as utils from './utils'; +import * as patchRules from '../../rules/patch_rules'; import { getFindResult, @@ -26,7 +28,13 @@ describe('patch_rules', () => { let clients = clientsServiceMock.createClients(); beforeEach(() => { + // jest carries state between mocked implementations when using + // spyOn. So now we're doing all three of these. + // https://github.com/facebook/jest/issues/7136#issuecomment-565976599 jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); + server = createMockServer(); getClients = clientsServiceMock.createGetScoped(); clients = clientsServiceMock.createClients(); @@ -63,6 +71,32 @@ describe('patch_rules', () => { const { statusCode } = await inject(getPatchRequest()); expect(statusCode).toBe(404); }); + + test('returns 500 when transform fails', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.actionsClient.update.mockResolvedValue(updateActionResult()); + clients.alertsClient.update.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + jest.spyOn(utils, 'transform').mockReturnValue(null); + const { payload, statusCode } = await server.inject(getPatchRequest()); + expect(JSON.parse(payload).message).toBe('Internal error transforming rules'); + expect(statusCode).toBe(500); + }); + + test('catches error if patchRules throws error', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.actionsClient.update.mockResolvedValue(updateActionResult()); + clients.alertsClient.update.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + jest.spyOn(patchRules, 'patchRules').mockImplementation(async () => { + throw new Error('Test error'); + }); + const { payload, statusCode } = await server.inject(getPatchRequest()); + expect(JSON.parse(payload).message).toBe('Test error'); + expect(statusCode).toBe(500); + }); }); describe('validation', () => { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/read_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/read_rules_route.test.ts index 7c4653af97f21..0366d3648e1ea 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/read_rules_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/read_rules_route.test.ts @@ -7,6 +7,9 @@ import { ServerInjectOptions } from 'hapi'; import { omit } from 'lodash/fp'; +import * as utils from './utils'; +import * as readRules from '../../rules/read_rules'; + import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { readRulesRoute } from './read_rules_route'; import { @@ -24,8 +27,12 @@ describe('read_signals', () => { let clients = clientsServiceMock.createClients(); beforeEach(() => { + // jest carries state between mocked implementations when using + // spyOn. So now we're doing all three of these. + // https://github.com/facebook/jest/issues/7136#issuecomment-565976599 jest.resetAllMocks(); - + jest.restoreAllMocks(); + jest.clearAllMocks(); server = createMockServer(); getClients = clientsServiceMock.createGetScoped(); clients = clientsServiceMock.createClients(); @@ -50,6 +57,38 @@ describe('read_signals', () => { const { statusCode } = await inject(getReadRequest()); expect(statusCode).toBe(404); }); + + test('returns error if readRules returns null', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + jest.spyOn(readRules, 'readRules').mockResolvedValue(null); + const { payload, statusCode } = await server.inject(getReadRequest()); + expect(JSON.parse(payload).message).toBe('rule_id: "rule-1" not found'); + expect(statusCode).toBe(404); + }); + + test('returns 500 when transform fails', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + jest.spyOn(utils, 'transform').mockReturnValue(null); + const { payload, statusCode } = await server.inject(getReadRequest()); + expect(JSON.parse(payload).message).toBe('Internal error transforming rules'); + expect(statusCode).toBe(500); + }); + + test('catches error if readRules throws error', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + jest.spyOn(readRules, 'readRules').mockImplementation(async () => { + throw new Error('Test error'); + }); + const { payload, statusCode } = await server.inject(getReadRequest()); + expect(JSON.parse(payload).message).toBe('Test error'); + expect(statusCode).toBe(500); + }); }); describe('validation', () => { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk.test.ts index 9ff7ebc37aab1..32a633799ad44 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk.test.ts @@ -75,9 +75,9 @@ describe('update_rules_bulk', () => { test('returns 404 if alertClient is not available on the route', async () => { getClients.mockResolvedValue(omit('alertsClient', clients)); - const { route, inject } = createMockServer(); + const { route } = createMockServer(); updateRulesRoute(route, config, getClients); - const { statusCode } = await inject(getUpdateBulkRequest()); + const { statusCode } = await server.inject(getUpdateBulkRequest()); expect(statusCode).toBe(404); }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.test.ts index 7cadfa94467a7..c3a92ed9a61ae 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.test.ts @@ -7,6 +7,9 @@ import { ServerInjectOptions } from 'hapi'; import { omit } from 'lodash/fp'; +import * as utils from './utils'; +import * as updateRules from '../../rules/update_rules'; + import { updateRulesRoute } from './update_rules_route'; import { getFindResult, @@ -27,7 +30,12 @@ describe('update_rules', () => { let clients = clientsServiceMock.createClients(); beforeEach(() => { + // jest carries state between mocked implementations when using + // spyOn. So now we're doing all three of these. + // https://github.com/facebook/jest/issues/7136#issuecomment-565976599 jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); server = createMockServer(); config = createMockConfig(); @@ -66,6 +74,28 @@ describe('update_rules', () => { const { statusCode } = await inject(getUpdateRequest()); expect(statusCode).toBe(404); }); + + test('returns 500 when transform fails', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + jest.spyOn(utils, 'transform').mockReturnValue(null); + const { payload, statusCode } = await server.inject(getUpdateRequest()); + expect(JSON.parse(payload).message).toBe('Internal error transforming rules'); + expect(statusCode).toBe(500); + }); + + test('catches error if readRules throws error', async () => { + clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + clients.alertsClient.get.mockResolvedValue(getResult()); + clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + jest.spyOn(updateRules, 'updateRules').mockImplementation(async () => { + throw new Error('Test error'); + }); + const { payload, statusCode } = await server.inject(getUpdateRequest()); + expect(JSON.parse(payload).message).toBe('Test error'); + expect(statusCode).toBe(500); + }); }); describe('validation', () => { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts index 593c55bcae9f2..b5b687c284b25 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts @@ -1251,9 +1251,10 @@ describe('utils', () => { this.push(null); }, }); - const rulesObjectsStream = createRulesStreamFromNdJson(ndJsonStream, 1000); + const rulesObjectsStream = createRulesStreamFromNdJson(1000); const parsedObjects = await createPromiseFromStreams([ - rulesObjectsStream, + ndJsonStream, + ...rulesObjectsStream, ]); const [errors, output] = getTupleDuplicateErrorsAndUniqueRules(parsedObjects, false); const isInstanceOfError = output[0] instanceof Error; @@ -1272,9 +1273,10 @@ describe('utils', () => { this.push(null); }, }); - const rulesObjectsStream = createRulesStreamFromNdJson(ndJsonStream, 1000); + const rulesObjectsStream = createRulesStreamFromNdJson(1000); const parsedObjects = await createPromiseFromStreams([ - rulesObjectsStream, + ndJsonStream, + ...rulesObjectsStream, ]); const [errors, output] = getTupleDuplicateErrorsAndUniqueRules(parsedObjects, false); @@ -1290,6 +1292,30 @@ describe('utils', () => { ]); }); + test('returns tuple of duplicate conflict error and single rule when rules with matching ids passed in and `overwrite` is false', async () => { + const rule = getSimpleRule('rule-1'); + delete rule.rule_id; + const rule2 = getSimpleRule('rule-1'); + delete rule2.rule_id; + const ndJsonStream = new Readable({ + read() { + this.push(`${JSON.stringify(rule)}\n`); + this.push(`${JSON.stringify(rule2)}\n`); + this.push(null); + }, + }); + const rulesObjectsStream = createRulesStreamFromNdJson(1000); + const parsedObjects = await createPromiseFromStreams([ + ndJsonStream, + ...rulesObjectsStream, + ]); + const [errors, output] = getTupleDuplicateErrorsAndUniqueRules(parsedObjects, false); + const isInstanceOfError = output[0] instanceof Error; + + expect(isInstanceOfError).toEqual(true); + expect(errors).toEqual([]); + }); + test('returns tuple of empty duplicate errors array and single rule when rules with matching rule-ids passed in and `overwrite` is true', async () => { const rule = getSimpleRule('rule-1'); const rule2 = getSimpleRule('rule-1'); @@ -1300,9 +1326,10 @@ describe('utils', () => { this.push(null); }, }); - const rulesObjectsStream = createRulesStreamFromNdJson(ndJsonStream, 1000); + const rulesObjectsStream = createRulesStreamFromNdJson(1000); const parsedObjects = await createPromiseFromStreams([ - rulesObjectsStream, + ndJsonStream, + ...rulesObjectsStream, ]); const [errors, output] = getTupleDuplicateErrorsAndUniqueRules(parsedObjects, true); @@ -1320,9 +1347,10 @@ describe('utils', () => { this.push(null); }, }); - const rulesObjectsStream = createRulesStreamFromNdJson(ndJsonStream, 1000); + const rulesObjectsStream = createRulesStreamFromNdJson(1000); const parsedObjects = await createPromiseFromStreams([ - rulesObjectsStream, + ndJsonStream, + ...rulesObjectsStream, ]); const [errors, output] = getTupleDuplicateErrorsAndUniqueRules(parsedObjects, false); const isInstanceOfError = output[0] instanceof Error; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts index 198cdbfb9771d..ab80e1570c31c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts @@ -180,9 +180,7 @@ export const transform = ( if (!ruleStatus && isAlertType(alert)) { return transformAlertToRule(alert); } - if (isAlertType(alert) && isRuleStatusFindType(ruleStatus)) { - return transformAlertToRule(alert, ruleStatus.saved_objects[0]); - } else if (isAlertType(alert) && isRuleStatusSavedObjectType(ruleStatus)) { + if (isAlertType(alert) && isRuleStatusSavedObjectType(ruleStatus)) { return transformAlertToRule(alert, ruleStatus); } else { return null; @@ -195,7 +193,7 @@ export const transformOrBulkError = ( ruleStatus?: unknown ): Partial | BulkError => { if (isAlertType(alert)) { - if (isRuleStatusFindType(ruleStatus)) { + if (isRuleStatusFindType(ruleStatus) && ruleStatus?.saved_objects.length > 0) { return transformAlertToRule(alert, ruleStatus?.saved_objects[0] ?? ruleStatus); } else { return transformAlertToRule(alert); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals.test.ts index 3e7ed4de6d8c6..7086c62f81711 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals.test.ts @@ -25,7 +25,12 @@ describe('set signal status', () => { let clients = clientsServiceMock.createClients(); beforeEach(() => { + // jest carries state between mocked implementations when using + // spyOn. So now we're doing all three of these. + // https://github.com/facebook/jest/issues/7136#issuecomment-565976599 jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); jest.spyOn(myUtils, 'getIndex').mockReturnValue('fakeindex'); server = createMockServer(); @@ -50,6 +55,15 @@ describe('set signal status', () => { const { statusCode } = await server.inject(getSetSignalStatusByQueryRequest()); expect(statusCode).toBe(200); }); + + test('catches error if callAsCurrentUser throws error', async () => { + clients.clusterClient.callAsCurrentUser.mockImplementation(async () => { + throw new Error('Test error'); + }); + const { payload, statusCode } = await server.inject(getSetSignalStatusByQueryRequest()); + expect(JSON.parse(payload).message).toBe('Test error'); + expect(statusCode).toBe(500); + }); }); describe('validation', () => { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals_route.ts index dd3b8d3c99e0c..ee3fd349a26ee 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals_route.ts @@ -28,7 +28,7 @@ export const setSignalsStatusRouteDef = ( payload: setSignalsStatusSchema, }, }, - async handler(request: SignalsStatusRequest) { + async handler(request: SignalsStatusRequest, headers) { const { signal_ids: signalIds, query, status } = request.payload; const { clusterClient, spacesClient } = await getClients(request); const index = getIndex(spacesClient.getSpaceId, config); @@ -45,7 +45,7 @@ export const setSignalsStatusRouteDef = ( }; } try { - return clusterClient.callAsCurrentUser('updateByQuery', { + const updateByQueryResponse = await clusterClient.callAsCurrentUser('updateByQuery', { index, body: { script: { @@ -56,9 +56,15 @@ export const setSignalsStatusRouteDef = ( }, ignoreUnavailable: true, }); - } catch (exc) { - // error while getting or updating signal with id: id in signal index .siem-signals - return transformError(exc); + return updateByQueryResponse; + } catch (err) { + const error = transformError(err); + return headers + .response({ + message: error.message, + status_code: error.statusCode, + }) + .code(error.statusCode); } }, }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.test.ts index 9439adfcec3cb..210ac9f3d7b01 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.test.ts @@ -127,5 +127,18 @@ describe('query for signal', () => { const { statusCode } = await server.inject(request); expect(statusCode).toBe(400); }); + test('catches error if deleteRules throws error', async () => { + const request: ServerInjectOptions = { + method: 'POST', + url: DETECTION_ENGINE_QUERY_SIGNALS_URL, + payload: { ...typicalSignalsQueryAggs(), ...typicalSignalsQuery() }, + }; + clients.clusterClient.callAsCurrentUser.mockImplementation(async () => { + throw new Error('Test error'); + }); + const { payload, statusCode } = await server.inject(request); + expect(JSON.parse(payload).message).toBe('Test error'); + expect(statusCode).toBe(500); + }); }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.ts index adb6e5f32921a..7636329ecc306 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.ts @@ -28,21 +28,27 @@ export const querySignalsRouteDef = ( payload: querySignalsSchema, }, }, - async handler(request: SignalsQueryRequest) { + async handler(request: SignalsQueryRequest, headers) { const { query, aggs, _source, track_total_hits, size } = request.payload; const { clusterClient, spacesClient } = await getClients(request); const index = getIndex(spacesClient.getSpaceId, config); try { - return clusterClient.callAsCurrentUser('search', { + const searchSignalsIndexResult = await clusterClient.callAsCurrentUser('search', { index, body: { query, aggs, _source, track_total_hits, size }, ignoreUnavailable: true, }); - } catch (exc) { - // error while getting or updating signal with id: id in signal index .siem-signals - return transformError(exc); + return searchSignalsIndexResult; + } catch (err) { + const error = transformError(err); + return headers + .response({ + message: error.message, + status_code: error.statusCode, + }) + .code(error.statusCode); } }, }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.test.ts index 957ddd4ee6caa..3148083b4db26 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.test.ts @@ -15,6 +15,7 @@ import { ImportSuccessError, createImportErrorObject, transformImportError, + convertToSnakeCase, } from './utils'; import { createMockConfig } from './__mocks__'; @@ -312,4 +313,15 @@ describe('utils', () => { expect(index).toEqual('mockSignalsIndex-myspace'); }); }); + + describe('convertToSnakeCase', () => { + it('converts camelCase to snakeCase', () => { + const values = { myTestCamelCaseKey: 'something' }; + expect(convertToSnakeCase(values)).toEqual({ my_test_camel_case_key: 'something' }); + }); + it('returns empty object when object is empty', () => { + const values = {}; + expect(convertToSnakeCase(values)).toEqual({}); + }); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.ts index 55832ab67dc6b..36e1a814d8ec2 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.ts @@ -5,6 +5,7 @@ */ import Boom from 'boom'; +import { snakeCase } from 'lodash/fp'; import { APP_ID, SIGNALS_INDEX_KEY } from '../../../../common/constants'; import { LegacyServices } from '../../../types'; @@ -211,3 +212,11 @@ export const getIndex = (getSpaceId: () => string, config: LegacyServices['confi return `${signalsIndex}-${spaceId}`; }; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const convertToSnakeCase = >(obj: T): Partial | null => { + return Object.keys(obj).reduce((acc, item) => { + const newKey = snakeCase(item); + return { ...acc, [newKey]: obj[item] }; + }, {}); +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts index d4b7c252e3e38..b1dc62f6fc90f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts @@ -5,12 +5,10 @@ */ import { Readable } from 'stream'; import { createRulesStreamFromNdJson } from './create_rules_stream_from_ndjson'; -import { createPromiseFromStreams, createConcatStream } from 'src/legacy/utils/streams'; +import { createPromiseFromStreams } from 'src/legacy/utils/streams'; import { ImportRuleAlertRest } from '../types'; -const readStreamToCompletion = (stream: Readable) => { - return createPromiseFromStreams([stream, createConcatStream([])]); -}; +type PromiseFromStreams = ImportRuleAlertRest | Error; export const getOutputSample = (): Partial => ({ rule_id: 'rule-1', @@ -43,8 +41,11 @@ describe('create_rules_stream_from_ndjson', () => { this.push(null); }, }); - const rulesObjectsStream = createRulesStreamFromNdJson(ndJsonStream, 1000); - const result = await readStreamToCompletion(rulesObjectsStream); + const rulesObjectsStream = createRulesStreamFromNdJson(1000); + const result = await createPromiseFromStreams([ + ndJsonStream, + ...rulesObjectsStream, + ]); expect(result).toEqual([ { rule_id: 'rule-1', @@ -95,6 +96,22 @@ describe('create_rules_stream_from_ndjson', () => { ]); }); + test('returns error when ndjson stream is larger than limit', async () => { + const sample1 = getOutputSample(); + const sample2 = getOutputSample(); + sample2.rule_id = 'rule-2'; + const ndJsonStream = new Readable({ + read() { + this.push(getSampleAsNdjson(sample1)); + this.push(getSampleAsNdjson(sample2)); + }, + }); + const rulesObjectsStream = createRulesStreamFromNdJson(1); + await expect( + createPromiseFromStreams([ndJsonStream, ...rulesObjectsStream]) + ).rejects.toThrowError("Can't import more than 1 rules"); + }); + test('skips empty lines', async () => { const sample1 = getOutputSample(); const sample2 = getOutputSample(); @@ -108,8 +125,11 @@ describe('create_rules_stream_from_ndjson', () => { this.push(null); }, }); - const rulesObjectsStream = createRulesStreamFromNdJson(ndJsonStream, 1000); - const result = await readStreamToCompletion(rulesObjectsStream); + const rulesObjectsStream = createRulesStreamFromNdJson(1000); + const result = await createPromiseFromStreams([ + ndJsonStream, + ...rulesObjectsStream, + ]); expect(result).toEqual([ { rule_id: 'rule-1', @@ -172,8 +192,11 @@ describe('create_rules_stream_from_ndjson', () => { this.push(null); }, }); - const rulesObjectsStream = createRulesStreamFromNdJson(ndJsonStream, 1000); - const result = await readStreamToCompletion(rulesObjectsStream); + const rulesObjectsStream = createRulesStreamFromNdJson(1000); + const result = await createPromiseFromStreams([ + ndJsonStream, + ...rulesObjectsStream, + ]); expect(result).toEqual([ { rule_id: 'rule-1', @@ -236,8 +259,11 @@ describe('create_rules_stream_from_ndjson', () => { this.push(null); }, }); - const rulesObjectsStream = createRulesStreamFromNdJson(ndJsonStream, 1000); - const result = await readStreamToCompletion(rulesObjectsStream); + const rulesObjectsStream = createRulesStreamFromNdJson(1000); + const result = await createPromiseFromStreams([ + ndJsonStream, + ...rulesObjectsStream, + ]); const resultOrError = result as Error[]; expect(resultOrError[0]).toEqual({ rule_id: 'rule-1', @@ -300,8 +326,11 @@ describe('create_rules_stream_from_ndjson', () => { this.push(null); }, }); - const rulesObjectsStream = createRulesStreamFromNdJson(ndJsonStream, 1000); - const result = await readStreamToCompletion(rulesObjectsStream); + const rulesObjectsStream = createRulesStreamFromNdJson(1000); + const result = await createPromiseFromStreams([ + ndJsonStream, + ...rulesObjectsStream, + ]); const resultOrError = result as TypeError[]; expect(resultOrError[0]).toEqual({ rule_id: 'rule-1', @@ -366,8 +395,11 @@ describe('create_rules_stream_from_ndjson', () => { this.push(null); }, }); - const rulesObjectsStream = createRulesStreamFromNdJson(ndJsonStream, 1000); - const result = await readStreamToCompletion(rulesObjectsStream); + const rulesObjectsStream = createRulesStreamFromNdJson(1000); + const result = await createPromiseFromStreams([ + ndJsonStream, + ...rulesObjectsStream, + ]); const resultOrError = result as TypeError[]; expect(resultOrError[1] instanceof TypeError).toEqual(true); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.ts index 6d58171a3245d..ae0dfa20852aa 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Readable, Transform } from 'stream'; +import { Transform } from 'stream'; import { has, isString } from 'lodash/fp'; import { ImportRuleAlertRest } from '../types'; import { @@ -74,15 +74,13 @@ export const createLimitStream = (limit: number): Transform => { * Inspiration and the pattern of code followed is from: * saved_objects/lib/create_saved_objects_stream_from_ndjson.ts */ -export const createRulesStreamFromNdJson = ( - ndJsonStream: Readable, - ruleLimit: number -): Transform => { - return ndJsonStream - .pipe(createSplitStream('\n')) - .pipe(parseNdjsonStrings()) - .pipe(filterExportedCounts()) - .pipe(validateRules()) - .pipe(createLimitStream(ruleLimit)) - .pipe(createConcatStream([])); +export const createRulesStreamFromNdJson = (ruleLimit: number) => { + return [ + createSplitStream('\n'), + parseNdjsonStrings(), + filterExportedCounts(), + validateRules(), + createLimitStream(ruleLimit), + createConcatStream([]), + ]; }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts index 98f5df4852530..44d3013263c65 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts @@ -10,9 +10,15 @@ import { getFindResultWithSingleHit, FindHit, } from '../routes/__mocks__/request_responses'; +import * as readRules from './read_rules'; import { alertsClientMock } from '../../../../../../../plugins/alerting/server/mocks'; describe('get_export_by_object_ids', () => { + beforeEach(() => { + jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); + }); describe('getExportByObjectIds', () => { test('it exports object ids into an expected string with new line characters', async () => { const alertsClient = alertsClientMock.create(); @@ -119,6 +125,23 @@ describe('get_export_by_object_ids', () => { expect(exports).toEqual(expected); }); + test('it returns error when readRules throws error', async () => { + const alertsClient = alertsClientMock.create(); + alertsClient.get.mockResolvedValue(getResult()); + alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + jest.spyOn(readRules, 'readRules').mockImplementation(async () => { + throw new Error('Test error'); + }); + const objects = [{ rule_id: 'rule-1' }]; + const exports = await getRulesFromObjects(alertsClient, objects); + const expected: RulesErrors = { + exportedCount: 0, + missingRules: [{ rule_id: objects[0].rule_id }], + rules: [], + }; + expect(exports).toEqual(expected); + }); + test('it does not transform the rule if the rule is an immutable rule and designates it as a missing rule', async () => { const alertsClient = alertsClientMock.create(); const result = getResult(); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.test.ts index 45507a69f50c2..aa1cce6f15238 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.test.ts @@ -8,7 +8,23 @@ import { readRules } from './read_rules'; import { alertsClientMock } from '../../../../../../../plugins/alerting/server/mocks'; import { getResult, getFindResultWithSingleHit } from '../routes/__mocks__/request_responses'; +class TestError extends Error { + constructor() { + // Pass remaining arguments (including vendor specific ones) to parent constructor + super(); + + this.name = 'CustomError'; + this.output = { statusCode: 404 }; + } + public output: { statusCode: number }; +} + describe('read_rules', () => { + beforeEach(() => { + jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); + }); describe('readRules', () => { test('should return the output from alertsClient if id is set but ruleId is undefined', async () => { const alertsClient = alertsClientMock.create(); @@ -21,6 +37,49 @@ describe('read_rules', () => { }); expect(rule).toEqual(getResult()); }); + test('should return null if saved object found by alerts client given id is not alert type', async () => { + const alertsClient = alertsClientMock.create(); + const { alertTypeId, ...rest } = getResult(); + // @ts-ignore + alertsClient.get.mockImplementation(() => rest); + + const rule = await readRules({ + alertsClient, + id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + ruleId: undefined, + }); + expect(rule).toEqual(null); + }); + + test('should return error if alerts client throws 404 error on get', async () => { + const alertsClient = alertsClientMock.create(); + alertsClient.get.mockImplementation(() => { + throw new TestError(); + }); + + const rule = await readRules({ + alertsClient, + id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + ruleId: undefined, + }); + expect(rule).toEqual(null); + }); + + test('should return error if alerts client throws error on get', async () => { + const alertsClient = alertsClientMock.create(); + alertsClient.get.mockImplementation(() => { + throw new Error('Test error'); + }); + try { + await readRules({ + alertsClient, + id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + ruleId: undefined, + }); + } catch (exc) { + expect(exc.message).toEqual('Test error'); + } + }); test('should return the output from alertsClient if id is set but ruleId is null', async () => { const alertsClient = alertsClientMock.create(); @@ -47,6 +106,20 @@ describe('read_rules', () => { expect(rule).toEqual(getResult()); }); + test('should return null if the output from alertsClient with ruleId set is empty', async () => { + const alertsClient = alertsClientMock.create(); + alertsClient.get.mockResolvedValue(getResult()); + // @ts-ignore + alertsClient.find.mockResolvedValue({ data: [] }); + + const rule = await readRules({ + alertsClient, + id: undefined, + ruleId: 'rule-1', + }); + expect(rule).toEqual(null); + }); + test('should return the output from alertsClient if id is null but ruleId is set', async () => { const alertsClient = alertsClientMock.create(); alertsClient.get.mockResolvedValue(getResult()); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.ts index cbe6dbda8449f..94e4e6357a4a0 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.ts @@ -31,7 +31,7 @@ export const readRules = async ({ return null; } } catch (err) { - if (err.output.statusCode === 404) { + if (err?.output?.statusCode === 404) { return null; } else { // throw non-404 as they would be 500 or other internal errors diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts index fa22765c143e1..3d95e9868a1d6 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts @@ -197,10 +197,6 @@ export const isAlertType = (obj: unknown): obj is RuleAlertType => { return get('alertTypeId', obj) === SIGNALS_ID; }; -export const isRuleStatusAttributes = (obj: unknown): obj is IRuleStatusAttributes => { - return get('lastSuccessMessage', obj) != null; -}; - export const isRuleStatusSavedObjectType = ( obj: unknown ): obj is SavedObject => { diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/import_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/import_rules.ts index 79a1e667e5458..a1cb60483c332 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/import_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/import_rules.ts @@ -74,6 +74,17 @@ export default ({ getService }: FtrProviderContext): void => { }); }); + it('should report that it failed to import a thousand and one (10001) simple rules', async () => { + const { body } = await supertest + .post(`${DETECTION_ENGINE_RULES_URL}/_import`) + .set('kbn-xsrf', 'true') + .attach('file', getSimpleRuleAsNdjson(new Array(10001).fill('rule-1')), 'rules.ndjson') + .query() + .expect(500); + + expect(body).to.eql({ message: "Can't import more than 10000 rules", status_code: 500 }); + }); + it('should be able to read an imported rule back out correctly', async () => { await supertest .post(`${DETECTION_ENGINE_RULES_URL}/_import`) From b17aa3551387bbe752b86950fb2d8b0ee600a629 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher Date: Tue, 25 Feb 2020 15:28:41 +0000 Subject: [PATCH 057/123] [Logs / Metrics UI] Handle index.scss (#58219) * Ensure our index.scss file is handled --- .../plugins/infra/public/apps/start_app.tsx | 9 ++---- x-pack/plugins/infra/public/index.scss | 29 +------------------ 2 files changed, 4 insertions(+), 34 deletions(-) diff --git a/x-pack/plugins/infra/public/apps/start_app.tsx b/x-pack/plugins/infra/public/apps/start_app.tsx index 66e699abd22b4..a797e4c9d4ba7 100644 --- a/x-pack/plugins/infra/public/apps/start_app.tsx +++ b/x-pack/plugins/infra/public/apps/start_app.tsx @@ -26,6 +26,7 @@ import { KibanaContextProvider, } from '../../../../../src/plugins/kibana_react/public'; import { AppRouter } from '../routers'; +import '../index.scss'; export const CONTAINER_CLASSNAME = 'infra-container-element'; @@ -74,12 +75,8 @@ export async function startApp( ); - // Ensure the element we're handed from application mounting takes up - // the full size it can, so that our inner application styles work as - // expected. - element.style.height = '100%'; - element.style.display = 'flex'; - element.style.overflowY = 'hidden'; // Prevent having scroll within a container having scroll. It messes up with drag-n-drop elements + // Ensure the element we're handed from application mounting is assigned a class + // for our index.scss styles to apply to. element.className += ` ${CONTAINER_CLASSNAME}`; ReactDOM.render(, element); diff --git a/x-pack/plugins/infra/public/index.scss b/x-pack/plugins/infra/public/index.scss index afee4ab8b0389..05e045c1bd53b 100644 --- a/x-pack/plugins/infra/public/index.scss +++ b/x-pack/plugins/infra/public/index.scss @@ -3,22 +3,13 @@ /* Infra plugin styles */ -// Prefix all styles with "inf" to avoid conflicts. -// Examples -// infChart -// infChart__legend -// infChart__legend--small -// infChart__legend-isLoading - -.infReactRoot { +.infra-container-element { background-color: $euiColorEmptyShade; position: absolute; top: 0; left: 0; bottom: 0; right: 0; - // display: flex; - // flex-direction: column; align-items: flex-start; flex: 1 0 auto; overflow-x: hidden; @@ -27,21 +18,3 @@ flex-direction: column; } -// This is a temporary workaround for https://github.com/elastic/kibana/issues/39808 -// A real fix will most likely depend on changes in elastic-charts. - -.infrastructureChart .echTooltip { - max-width: 90vw; -} - -.infrastructureChart .echTooltip__label { - overflow-x: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.metricsExplorerTitleAnchor { - white-space: nowrap; - text-overflow: ellipsis; - display: inline; -} From 21d98d787e4f8c0b20be89d9c12829ba6b3aeefd Mon Sep 17 00:00:00 2001 From: MadameSheema Date: Tue, 25 Feb 2020 17:10:18 +0100 Subject: [PATCH 058/123] skips 'ResizeObserver loop limit exceeded' error (#58465) --- x-pack/legacy/plugins/siem/cypress/support/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x-pack/legacy/plugins/siem/cypress/support/index.js b/x-pack/legacy/plugins/siem/cypress/support/index.js index 9b86c2ffa94c6..37fa920a8bc31 100644 --- a/x-pack/legacy/plugins/siem/cypress/support/index.js +++ b/x-pack/legacy/plugins/siem/cypress/support/index.js @@ -26,5 +26,11 @@ Cypress.Cookies.defaults({ whitelist: 'sid', }); +Cypress.on('uncaught:exception', err => { + if (err.message.includes('ResizeObserver loop limit exceeded')) { + return false; + } +}); + // Alternatively you can use CommonJS syntax: // require('./commands') From 712c0851a7d5b34009d948485eda797ed85d71fa Mon Sep 17 00:00:00 2001 From: MadameSheema Date: Tue, 25 Feb 2020 17:15:31 +0100 Subject: [PATCH 059/123] [SIEM] Deletes duplicated tests (#58453) * deletes duplicated test * deletes duplicated fields browser test --- .../plugins/siem/cypress/integration/events_viewer.spec.ts | 7 ------- .../siem/cypress/integration/fields_browser.spec.ts | 7 ------- 2 files changed, 14 deletions(-) diff --git a/x-pack/legacy/plugins/siem/cypress/integration/events_viewer.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/events_viewer.spec.ts index e44c8f4459ba9..446db89ec09dc 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/events_viewer.spec.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/events_viewer.spec.ts @@ -8,7 +8,6 @@ import { FIELDS_BROWSER_CHECKBOX, FIELDS_BROWSER_CONTAINER, FIELDS_BROWSER_SELECTED_CATEGORY_TITLE, - FIELDS_BROWSER_TITLE, } from '../screens/fields_browser'; import { HEADER_SUBTITLE, @@ -61,12 +60,6 @@ describe('Events Viewer', () => { cy.get(FIELDS_BROWSER_CONTAINER).should('not.exist'); }); - it('renders the fields browser with the expected title when the Events Viewer Fields Browser button is clicked', () => { - cy.get(FIELDS_BROWSER_TITLE) - .invoke('text') - .should('eq', 'Customize Columns'); - }); - it('displays the `default ECS` category (by default)', () => { cy.get(FIELDS_BROWSER_SELECTED_CATEGORY_TITLE) .invoke('text') diff --git a/x-pack/legacy/plugins/siem/cypress/integration/fields_browser.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/fields_browser.spec.ts index 095fc30356fd4..8dddd97f2d830 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/fields_browser.spec.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/fields_browser.spec.ts @@ -15,7 +15,6 @@ import { FIELDS_BROWSER_SELECTED_CATEGORY_TITLE, FIELDS_BROWSER_SELECTED_CATEGORY_COUNT, FIELDS_BROWSER_SYSTEM_CATEGORIES_COUNT, - FIELDS_BROWSER_TITLE, } from '../screens/fields_browser'; import { @@ -58,12 +57,6 @@ describe('Fields Browser', () => { clearFieldsBrowser(); }); - it('renders the fields browser with the expected title when the Fields button is clicked', () => { - cy.get(FIELDS_BROWSER_TITLE) - .invoke('text') - .should('eq', 'Customize Columns'); - }); - it('displays the `default ECS` category (by default)', () => { cy.get(FIELDS_BROWSER_SELECTED_CATEGORY_TITLE) .invoke('text') From c1dede78fbbee6ca1c97fb9c5f31d72f39584566 Mon Sep 17 00:00:00 2001 From: liza-mae Date: Tue, 25 Feb 2020 09:21:30 -0700 Subject: [PATCH 060/123] Add a way to disable certificate verification for FTR. (#58386) * Add a way to disable certificate verification for FTR. * Remove other options Co-authored-by: Elastic Machine --- test/functional/services/remote/webdriver.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts index 1bd6358749e11..382543822d8ac 100644 --- a/test/functional/services/remote/webdriver.ts +++ b/test/functional/services/remote/webdriver.ts @@ -44,6 +44,7 @@ import { Browsers } from './browsers'; const throttleOption: string = process.env.TEST_THROTTLE_NETWORK as string; const headlessBrowser: string = process.env.TEST_BROWSER_HEADLESS as string; const remoteDebug: string = process.env.TEST_REMOTE_DEBUG as string; +const certValidation: string = process.env.NODE_TLS_REJECT_UNAUTHORIZED as string; const SECOND = 1000; const MINUTE = 60 * SECOND; const NO_QUEUE_COMMANDS = ['getLog', 'getStatus', 'newSession', 'quit']; @@ -98,6 +99,9 @@ async function attemptToCreateCommand( // See: https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md chromeOptions.push('headless', 'disable-gpu'); } + if (certValidation === '0') { + chromeOptions.push('ignore-certificate-errors'); + } if (remoteDebug === '1') { // Visit chrome://inspect in chrome to remotely view/debug chromeOptions.push('headless', 'disable-gpu', 'remote-debugging-port=9222'); From a714300155fee3854777f4478fcf766bbc68c892 Mon Sep 17 00:00:00 2001 From: Vadim Dalecky Date: Tue, 25 Feb 2020 17:48:56 +0100 Subject: [PATCH 061/123] =?UTF-8?q?fix:=20=F0=9F=90=9B=20make=20performanc?= =?UTF-8?q?e.now=20work=20on=20server=20(#58360)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 🐛 make performance.now work on server * fix: 🐛 change check for Node environment * fix: 🐛 simplify now() fn, remove require('perf_hohoks') --- .../expressions/common/execution/execution.ts | 8 +++--- src/plugins/kibana_utils/common/index.ts | 1 + src/plugins/kibana_utils/common/now.ts | 25 +++++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 src/plugins/kibana_utils/common/now.ts diff --git a/src/plugins/expressions/common/execution/execution.ts b/src/plugins/expressions/common/execution/execution.ts index 272448870e817..f70a32f2f09c1 100644 --- a/src/plugins/expressions/common/execution/execution.ts +++ b/src/plugins/expressions/common/execution/execution.ts @@ -21,7 +21,7 @@ import { keys, last, mapValues, reduce, zipObject } from 'lodash'; import { Executor } from '../executor'; import { createExecutionContainer, ExecutionContainer } from './container'; import { createError } from '../util'; -import { Defer } from '../../../kibana_utils/common'; +import { Defer, now } from '../../../kibana_utils/common'; import { RequestAdapter, DataAdapter } from '../../../inspector/common'; import { isExpressionValueError, ExpressionValueError } from '../expression_types/specs/error'; import { @@ -211,11 +211,11 @@ export class Execution< // actually have a `then` function which would be treated as a `Promise`. const { resolvedArgs } = await this.resolveArgs(fn, input, fnArgs); args = resolvedArgs; - timeStart = this.params.debug ? performance.now() : 0; + timeStart = this.params.debug ? now() : 0; const output = await this.invokeFunction(fn, input, resolvedArgs); if (this.params.debug) { - const timeEnd: number = performance.now(); + const timeEnd: number = now(); (link as ExpressionAstFunction).debug = { success: true, fn, @@ -229,7 +229,7 @@ export class Execution< if (getType(output) === 'error') return output; input = output; } catch (rawError) { - const timeEnd: number = this.params.debug ? performance.now() : 0; + const timeEnd: number = this.params.debug ? now() : 0; const error = createError(rawError) as ExpressionValueError; error.error.message = `[${fnName}] > ${error.error.message}`; diff --git a/src/plugins/kibana_utils/common/index.ts b/src/plugins/kibana_utils/common/index.ts index 3b07674315dce..50120edc0c056 100644 --- a/src/plugins/kibana_utils/common/index.ts +++ b/src/plugins/kibana_utils/common/index.ts @@ -25,3 +25,4 @@ export * from './typed_json'; export { createGetterSetter, Get, Set } from './create_getter_setter'; export { distinctUntilChangedWithInitialValue } from './distinct_until_changed_with_initial_value'; export { url } from './url'; +export { now } from './now'; diff --git a/src/plugins/kibana_utils/common/now.ts b/src/plugins/kibana_utils/common/now.ts new file mode 100644 index 0000000000000..e6c6d74552622 --- /dev/null +++ b/src/plugins/kibana_utils/common/now.ts @@ -0,0 +1,25 @@ +/* + * 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. + */ + +/** + * Function that returns number in milliseconds since some undefined point in + * time. Use this function for performance measurements. + */ +export const now: () => number = + typeof performance === 'object' ? performance.now.bind(performance) : Date.now; From c8f18208ab697ea823f7029ee6ae48f87d5fa5fe Mon Sep 17 00:00:00 2001 From: Vadim Dalecky Date: Tue, 25 Feb 2020 17:56:02 +0100 Subject: [PATCH 062/123] Embeddable action storage (#58438) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 stub out EmbeddableActionStorage class * test: 💍 add embeddable event storage .create() tests * feat: 🎸 add EmbeddableActionStorage.update() method * feat: 🎸 add .actionStorage to Embeddable class * feat: 🎸 add EmbeddableActionStorage.remove() method * feat: 🎸 add EmbeddableActionStorage.read() method * feat: 🎸 add .list() and .count() to EmbeddableActionStorage --- .../public/lib/embeddables/embeddable.tsx | 6 + .../embeddable_action_storage.test.ts | 536 ++++++++++++++++++ .../embeddables/embeddable_action_storage.ts | 126 ++++ .../public/lib/embeddables/i_embeddable.ts | 5 + 4 files changed, 673 insertions(+) create mode 100644 src/plugins/embeddable/public/lib/embeddables/embeddable_action_storage.test.ts create mode 100644 src/plugins/embeddable/public/lib/embeddables/embeddable_action_storage.ts diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx index 534e1cae3f62d..a1b332bb65617 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx @@ -22,6 +22,7 @@ import { Adapters } from '../types'; import { IContainer } from '../containers'; import { IEmbeddable, EmbeddableInput, EmbeddableOutput } from './i_embeddable'; import { ViewMode } from '../types'; +import { EmbeddableActionStorage } from './embeddable_action_storage'; function getPanelTitle(input: EmbeddableInput, output: EmbeddableOutput) { return input.hidePanelTitles ? '' : input.title === undefined ? output.defaultTitle : input.title; @@ -49,6 +50,11 @@ export abstract class Embeddable< // TODO: Rename to destroyed. private destoyed: boolean = false; + private __actionStorage?: EmbeddableActionStorage; + public get actionStorage(): EmbeddableActionStorage { + return this.__actionStorage || (this.__actionStorage = new EmbeddableActionStorage(this)); + } + constructor(input: TEmbeddableInput, output: TEmbeddableOutput, parent?: IContainer) { this.id = input.id; this.output = { diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable_action_storage.test.ts b/src/plugins/embeddable/public/lib/embeddables/embeddable_action_storage.test.ts new file mode 100644 index 0000000000000..56facc37fc666 --- /dev/null +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable_action_storage.test.ts @@ -0,0 +1,536 @@ +/* + * 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 { Embeddable } from './embeddable'; +import { EmbeddableInput } from './i_embeddable'; +import { ViewMode } from '../types'; +import { EmbeddableActionStorage, SerializedEvent } from './embeddable_action_storage'; +import { of } from '../../../../kibana_utils/common'; + +class TestEmbeddable extends Embeddable { + public readonly type = 'test'; + constructor() { + super({ id: 'test', viewMode: ViewMode.VIEW }, {}); + } + reload() {} +} + +describe('EmbeddableActionStorage', () => { + describe('.create()', () => { + test('method exists', () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + expect(typeof storage.create).toBe('function'); + }); + + test('can add event to embeddable', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + const event: SerializedEvent = { + eventId: 'EVENT_ID', + triggerId: 'TRIGGER-ID', + action: {} as any, + }; + + const events1 = embeddable.getInput().events || []; + expect(events1).toEqual([]); + + await storage.create(event); + + const events2 = embeddable.getInput().events || []; + expect(events2).toEqual([event]); + }); + + test('can create multiple events', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const event1: SerializedEvent = { + eventId: 'EVENT_ID1', + triggerId: 'TRIGGER-ID', + action: {} as any, + }; + const event2: SerializedEvent = { + eventId: 'EVENT_ID2', + triggerId: 'TRIGGER-ID', + action: {} as any, + }; + const event3: SerializedEvent = { + eventId: 'EVENT_ID3', + triggerId: 'TRIGGER-ID', + action: {} as any, + }; + + const events1 = embeddable.getInput().events || []; + expect(events1).toEqual([]); + + await storage.create(event1); + + const events2 = embeddable.getInput().events || []; + expect(events2).toEqual([event1]); + + await storage.create(event2); + await storage.create(event3); + + const events3 = embeddable.getInput().events || []; + expect(events3).toEqual([event1, event2, event3]); + }); + + test('throws when creating an event with the same ID', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + const event: SerializedEvent = { + eventId: 'EVENT_ID', + triggerId: 'TRIGGER-ID', + action: {} as any, + }; + + await storage.create(event); + const [, error] = await of(storage.create(event)); + + expect(error).toBeInstanceOf(Error); + expect(error.message).toMatchInlineSnapshot( + `"[EEXIST]: Event with [eventId = EVENT_ID] already exists on [embeddable.id = test, embeddable.title = undefined]."` + ); + }); + }); + + describe('.update()', () => { + test('method exists', () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + expect(typeof storage.update).toBe('function'); + }); + + test('can update an existing event', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const event1: SerializedEvent = { + eventId: 'EVENT_ID', + triggerId: 'TRIGGER-ID', + action: { + name: 'foo', + } as any, + }; + const event2: SerializedEvent = { + eventId: 'EVENT_ID', + triggerId: 'TRIGGER-ID', + action: { + name: 'bar', + } as any, + }; + + await storage.create(event1); + await storage.update(event2); + + const events = embeddable.getInput().events || []; + expect(events).toEqual([event2]); + }); + + test('updates event in place of the old event', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const event1: SerializedEvent = { + eventId: 'EVENT_ID1', + triggerId: 'TRIGGER-ID', + action: { + name: 'foo', + } as any, + }; + const event2: SerializedEvent = { + eventId: 'EVENT_ID2', + triggerId: 'TRIGGER-ID', + action: { + name: 'bar', + } as any, + }; + const event22: SerializedEvent = { + eventId: 'EVENT_ID2', + triggerId: 'TRIGGER-ID', + action: { + name: 'baz', + } as any, + }; + const event3: SerializedEvent = { + eventId: 'EVENT_ID3', + triggerId: 'TRIGGER-ID', + action: { + name: 'qux', + } as any, + }; + + await storage.create(event1); + await storage.create(event2); + await storage.create(event3); + + const events1 = embeddable.getInput().events || []; + expect(events1).toEqual([event1, event2, event3]); + + await storage.update(event22); + + const events2 = embeddable.getInput().events || []; + expect(events2).toEqual([event1, event22, event3]); + + await storage.update(event2); + + const events3 = embeddable.getInput().events || []; + expect(events3).toEqual([event1, event2, event3]); + }); + + test('throws when updating event, but storage is empty', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const event: SerializedEvent = { + eventId: 'EVENT_ID', + triggerId: 'TRIGGER-ID', + action: {} as any, + }; + + const [, error] = await of(storage.update(event)); + + expect(error).toBeInstanceOf(Error); + expect(error.message).toMatchInlineSnapshot( + `"[ENOENT]: Event with [eventId = EVENT_ID] could not be updated as it does not exist in [embeddable.id = test, embeddable.title = undefined]."` + ); + }); + + test('throws when updating event with ID that is not stored', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const event1: SerializedEvent = { + eventId: 'EVENT_ID1', + triggerId: 'TRIGGER-ID', + action: {} as any, + }; + const event2: SerializedEvent = { + eventId: 'EVENT_ID2', + triggerId: 'TRIGGER-ID', + action: {} as any, + }; + + await storage.create(event1); + const [, error] = await of(storage.update(event2)); + + expect(error).toBeInstanceOf(Error); + expect(error.message).toMatchInlineSnapshot( + `"[ENOENT]: Event with [eventId = EVENT_ID2] could not be updated as it does not exist in [embeddable.id = test, embeddable.title = undefined]."` + ); + }); + }); + + describe('.remove()', () => { + test('method exists', () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + expect(typeof storage.remove).toBe('function'); + }); + + test('can remove existing event', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const event: SerializedEvent = { + eventId: 'EVENT_ID', + triggerId: 'TRIGGER-ID', + action: {} as any, + }; + + await storage.create(event); + await storage.remove(event.eventId); + + const events = embeddable.getInput().events || []; + expect(events).toEqual([]); + }); + + test('removes correct events in a list of events', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const event1: SerializedEvent = { + eventId: 'EVENT_ID1', + triggerId: 'TRIGGER-ID', + action: { + name: 'foo', + } as any, + }; + const event2: SerializedEvent = { + eventId: 'EVENT_ID2', + triggerId: 'TRIGGER-ID', + action: { + name: 'bar', + } as any, + }; + const event3: SerializedEvent = { + eventId: 'EVENT_ID3', + triggerId: 'TRIGGER-ID', + action: { + name: 'qux', + } as any, + }; + + await storage.create(event1); + await storage.create(event2); + await storage.create(event3); + + const events1 = embeddable.getInput().events || []; + expect(events1).toEqual([event1, event2, event3]); + + await storage.remove(event2.eventId); + + const events2 = embeddable.getInput().events || []; + expect(events2).toEqual([event1, event3]); + + await storage.remove(event3.eventId); + + const events3 = embeddable.getInput().events || []; + expect(events3).toEqual([event1]); + + await storage.remove(event1.eventId); + + const events4 = embeddable.getInput().events || []; + expect(events4).toEqual([]); + }); + + test('throws when removing an event from an empty storage', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const [, error] = await of(storage.remove('EVENT_ID')); + + expect(error).toBeInstanceOf(Error); + expect(error.message).toMatchInlineSnapshot( + `"[ENOENT]: Event with [eventId = EVENT_ID] could not be removed as it does not exist in [embeddable.id = test, embeddable.title = undefined]."` + ); + }); + + test('throws when removing with ID that does not exist in storage', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const event: SerializedEvent = { + eventId: 'EVENT_ID', + triggerId: 'TRIGGER-ID', + action: {} as any, + }; + + await storage.create(event); + const [, error] = await of(storage.remove('WRONG_ID')); + await storage.remove(event.eventId); + + expect(error).toBeInstanceOf(Error); + expect(error.message).toMatchInlineSnapshot( + `"[ENOENT]: Event with [eventId = WRONG_ID] could not be removed as it does not exist in [embeddable.id = test, embeddable.title = undefined]."` + ); + }); + }); + + describe('.read()', () => { + test('method exists', () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + expect(typeof storage.read).toBe('function'); + }); + + test('can read an existing event out of storage', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const event: SerializedEvent = { + eventId: 'EVENT_ID', + triggerId: 'TRIGGER-ID', + action: {} as any, + }; + + await storage.create(event); + const event2 = await storage.read(event.eventId); + + expect(event2).toEqual(event); + }); + + test('throws when reading from empty storage', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const [, error] = await of(storage.read('EVENT_ID')); + + expect(error).toBeInstanceOf(Error); + expect(error.message).toMatchInlineSnapshot( + `"[ENOENT]: Event with [eventId = EVENT_ID] could not be found in [embeddable.id = test, embeddable.title = undefined]."` + ); + }); + + test('throws when reading event with ID not existing in storage', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const event: SerializedEvent = { + eventId: 'EVENT_ID', + triggerId: 'TRIGGER-ID', + action: {} as any, + }; + + await storage.create(event); + const [, error] = await of(storage.read('WRONG_ID')); + + expect(error).toBeInstanceOf(Error); + expect(error.message).toMatchInlineSnapshot( + `"[ENOENT]: Event with [eventId = WRONG_ID] could not be found in [embeddable.id = test, embeddable.title = undefined]."` + ); + }); + + test('returns correct event when multiple events are stored', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const event1: SerializedEvent = { + eventId: 'EVENT_ID1', + triggerId: 'TRIGGER-ID1', + action: {} as any, + }; + const event2: SerializedEvent = { + eventId: 'EVENT_ID2', + triggerId: 'TRIGGER-ID2', + action: {} as any, + }; + const event3: SerializedEvent = { + eventId: 'EVENT_ID3', + triggerId: 'TRIGGER-ID3', + action: {} as any, + }; + + await storage.create(event1); + await storage.create(event2); + await storage.create(event3); + + const event12 = await storage.read(event1.eventId); + const event22 = await storage.read(event2.eventId); + const event32 = await storage.read(event3.eventId); + + expect(event12).toEqual(event1); + expect(event22).toEqual(event2); + expect(event32).toEqual(event3); + + expect(event12).not.toEqual(event2); + }); + }); + + describe('.count()', () => { + test('method exists', () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + expect(typeof storage.count).toBe('function'); + }); + + test('returns 0 when storage is empty', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const count = await storage.count(); + + expect(count).toBe(0); + }); + + test('returns correct number of events in storage', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + expect(await storage.count()).toBe(0); + + await storage.create({ + eventId: 'EVENT_ID1', + triggerId: 'TRIGGER-ID1', + action: {} as any, + }); + + expect(await storage.count()).toBe(1); + + await storage.create({ + eventId: 'EVENT_ID2', + triggerId: 'TRIGGER-ID1', + action: {} as any, + }); + + expect(await storage.count()).toBe(2); + + await storage.remove('EVENT_ID1'); + + expect(await storage.count()).toBe(1); + + await storage.remove('EVENT_ID2'); + + expect(await storage.count()).toBe(0); + }); + }); + + describe('.list()', () => { + test('method exists', () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + expect(typeof storage.list).toBe('function'); + }); + + test('returns empty array when storage is empty', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const list = await storage.list(); + + expect(list).toEqual([]); + }); + + test('returns correct list of events in storage', async () => { + const embeddable = new TestEmbeddable(); + const storage = new EmbeddableActionStorage(embeddable); + + const event1: SerializedEvent = { + eventId: 'EVENT_ID1', + triggerId: 'TRIGGER-ID1', + action: {} as any, + }; + + const event2: SerializedEvent = { + eventId: 'EVENT_ID2', + triggerId: 'TRIGGER-ID1', + action: {} as any, + }; + + expect(await storage.list()).toEqual([]); + + await storage.create(event1); + + expect(await storage.list()).toEqual([event1]); + + await storage.create(event2); + + expect(await storage.list()).toEqual([event1, event2]); + + await storage.remove('EVENT_ID1'); + + expect(await storage.list()).toEqual([event2]); + + await storage.remove('EVENT_ID2'); + + expect(await storage.list()).toEqual([]); + }); + }); +}); diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable_action_storage.ts b/src/plugins/embeddable/public/lib/embeddables/embeddable_action_storage.ts new file mode 100644 index 0000000000000..520f92840c5f9 --- /dev/null +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable_action_storage.ts @@ -0,0 +1,126 @@ +/* + * 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 { Embeddable } from '..'; + +/** + * Below two interfaces are here temporarily, they will move to `ui_actions` + * plugin once #58216 is merged. + */ +export interface SerializedEvent { + eventId: string; + triggerId: string; + action: unknown; +} +export interface ActionStorage { + create(event: SerializedEvent): Promise; + update(event: SerializedEvent): Promise; + remove(eventId: string): Promise; + read(eventId: string): Promise; + count(): Promise; + list(): Promise; +} + +export class EmbeddableActionStorage implements ActionStorage { + constructor(private readonly embbeddable: Embeddable) {} + + async create(event: SerializedEvent) { + const input = this.embbeddable.getInput(); + const events = (input.events || []) as SerializedEvent[]; + const exists = !!events.find(({ eventId }) => eventId === event.eventId); + + if (exists) { + throw new Error( + `[EEXIST]: Event with [eventId = ${event.eventId}] already exists on ` + + `[embeddable.id = ${input.id}, embeddable.title = ${input.title}].` + ); + } + + this.embbeddable.updateInput({ + ...input, + events: [...events, event], + }); + } + + async update(event: SerializedEvent) { + const input = this.embbeddable.getInput(); + const events = (input.events || []) as SerializedEvent[]; + const index = events.findIndex(({ eventId }) => eventId === event.eventId); + + if (index === -1) { + throw new Error( + `[ENOENT]: Event with [eventId = ${event.eventId}] could not be ` + + `updated as it does not exist in ` + + `[embeddable.id = ${input.id}, embeddable.title = ${input.title}].` + ); + } + + this.embbeddable.updateInput({ + ...input, + events: [...events.slice(0, index), event, ...events.slice(index + 1)], + }); + } + + async remove(eventId: string) { + const input = this.embbeddable.getInput(); + const events = (input.events || []) as SerializedEvent[]; + const index = events.findIndex(event => eventId === event.eventId); + + if (index === -1) { + throw new Error( + `[ENOENT]: Event with [eventId = ${eventId}] could not be ` + + `removed as it does not exist in ` + + `[embeddable.id = ${input.id}, embeddable.title = ${input.title}].` + ); + } + + this.embbeddable.updateInput({ + ...input, + events: [...events.slice(0, index), ...events.slice(index + 1)], + }); + } + + async read(eventId: string): Promise { + const input = this.embbeddable.getInput(); + const events = (input.events || []) as SerializedEvent[]; + const event = events.find(ev => eventId === ev.eventId); + + if (!event) { + throw new Error( + `[ENOENT]: Event with [eventId = ${eventId}] could not be found in ` + + `[embeddable.id = ${input.id}, embeddable.title = ${input.title}].` + ); + } + + return event; + } + + private __list() { + const input = this.embbeddable.getInput(); + return (input.events || []) as SerializedEvent[]; + } + + async count(): Promise { + return this.__list().length; + } + + async list(): Promise { + return this.__list(); + } +} diff --git a/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts b/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts index 46cffab879684..62121cb0f23dd 100644 --- a/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts +++ b/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts @@ -30,6 +30,11 @@ export interface EmbeddableInput { hidePanelTitles?: boolean; isEmptyState?: boolean; + /** + * Reserved key for `ui_actions` events. + */ + events?: unknown; + /** * List of action IDs that this embeddable should not render. */ From bd40f557a5e4a7cbcabe1c6f6a5cc7d4d5f52320 Mon Sep 17 00:00:00 2001 From: Vadim Dalecky Date: Tue, 25 Feb 2020 17:57:40 +0100 Subject: [PATCH 063/123] Embeddable action storage (#58438) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 stub out EmbeddableActionStorage class * test: 💍 add embeddable event storage .create() tests * feat: 🎸 add EmbeddableActionStorage.update() method * feat: 🎸 add .actionStorage to Embeddable class * feat: 🎸 add EmbeddableActionStorage.remove() method * feat: 🎸 add EmbeddableActionStorage.read() method * feat: 🎸 add .list() and .count() to EmbeddableActionStorage From 120f03dc06f7f4a64e911454d6774c1d651acef1 Mon Sep 17 00:00:00 2001 From: Vadim Dalecky Date: Tue, 25 Feb 2020 18:02:25 +0100 Subject: [PATCH 064/123] Add component (#58335) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 💡 use .story for Storybook and standartize dir struct * feat: 🎸 add component * feat: 🎸 add component * refactor: 💡 improve FlyoutCreateDrilldownAction * test: 💍 add tests * docs: ✏️ add @todo for * feat: 🎸 make name editable in * test: 💍 add name field tests * chore: 🤖 change drilldown translation keys --- .../index.tsx | 22 ++-- .../drilldowns/public/actions/index.ts | 2 +- ...ples.tsx => drilldown_hello_bar.story.tsx} | 2 +- .../drilldown_hello_bar.tsx | 26 +++++ .../components/drilldown_hello_bar/index.tsx | 22 +--- ...xamples.tsx => drilldown_picker.story.tsx} | 2 +- .../drilldown_picker/drilldown_picker.tsx | 21 ++++ .../components/drilldown_picker/index.tsx | 16 +-- .../flyout_create_drilldown.story.tsx | 24 +++++ .../flyout_create_drilldown.tsx | 34 ++++++ .../flyout_create_drilldown/i18n.ts | 14 +++ .../flyout_create_drilldown/index.ts | 7 ++ .../flyout_frame/flyout_frame.story.tsx | 39 +++++++ .../flyout_frame/flyout_frame.test.tsx | 102 ++++++++++++++++++ .../components/flyout_frame/flyout_frame.tsx | 71 ++++++++++++ .../i18n.ts} | 8 +- .../public/components/flyout_frame/index.tsx | 7 ++ .../form_create_drilldown.story.tsx | 34 ++++++ .../form_create_drilldown.test.tsx | 68 ++++++++++++ .../form_create_drilldown.tsx | 52 +++++++++ .../components/form_create_drilldown/i18n.ts | 6 +- .../form_create_drilldown/index.tsx | 25 +---- .../public/service/drilldown_service.ts | 8 +- .../plugins/drilldowns/scripts/storybook.js | 2 +- 24 files changed, 528 insertions(+), 86 deletions(-) rename x-pack/plugins/drilldowns/public/actions/{open_flyout_add_drilldown => flyout_create_drilldown}/index.tsx (61%) rename x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/{__examples__/drilldown_hello_bar.examples.tsx => drilldown_hello_bar.story.tsx} (91%) create mode 100644 x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/drilldown_hello_bar.tsx rename x-pack/plugins/drilldowns/public/components/drilldown_picker/{__examples__/drilldown_picker.examples.tsx => drilldown_picker.story.tsx} (91%) create mode 100644 x-pack/plugins/drilldowns/public/components/drilldown_picker/drilldown_picker.tsx create mode 100644 x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/flyout_create_drilldown.story.tsx create mode 100644 x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/flyout_create_drilldown.tsx create mode 100644 x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/i18n.ts create mode 100644 x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/index.ts create mode 100644 x-pack/plugins/drilldowns/public/components/flyout_frame/flyout_frame.story.tsx create mode 100644 x-pack/plugins/drilldowns/public/components/flyout_frame/flyout_frame.test.tsx create mode 100644 x-pack/plugins/drilldowns/public/components/flyout_frame/flyout_frame.tsx rename x-pack/plugins/drilldowns/public/components/{form_create_drilldown/__examples__/form_create_drilldown.examples.tsx => flyout_frame/i18n.ts} (51%) create mode 100644 x-pack/plugins/drilldowns/public/components/flyout_frame/index.tsx create mode 100644 x-pack/plugins/drilldowns/public/components/form_create_drilldown/form_create_drilldown.story.tsx create mode 100644 x-pack/plugins/drilldowns/public/components/form_create_drilldown/form_create_drilldown.test.tsx create mode 100644 x-pack/plugins/drilldowns/public/components/form_create_drilldown/form_create_drilldown.tsx diff --git a/x-pack/plugins/drilldowns/public/actions/open_flyout_add_drilldown/index.tsx b/x-pack/plugins/drilldowns/public/actions/flyout_create_drilldown/index.tsx similarity index 61% rename from x-pack/plugins/drilldowns/public/actions/open_flyout_add_drilldown/index.tsx rename to x-pack/plugins/drilldowns/public/actions/flyout_create_drilldown/index.tsx index 06f134b10a4b7..0b9f54f51f61e 100644 --- a/x-pack/plugins/drilldowns/public/actions/open_flyout_add_drilldown/index.tsx +++ b/x-pack/plugins/drilldowns/public/actions/flyout_create_drilldown/index.tsx @@ -10,11 +10,11 @@ import { CoreStart } from 'src/core/public'; import { Action } from '../../../../../../src/plugins/ui_actions/public'; import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public'; import { IEmbeddable } from '../../../../../../src/plugins/embeddable/public'; -import { FormCreateDrilldown } from '../../components/form_create_drilldown'; +import { FlyoutCreateDrilldown } from '../../components/flyout_create_drilldown'; export const OPEN_FLYOUT_ADD_DRILLDOWN = 'OPEN_FLYOUT_ADD_DRILLDOWN'; -interface ActionContext { +export interface FlyoutCreateDrilldownActionContext { embeddable: IEmbeddable; } @@ -22,29 +22,31 @@ export interface OpenFlyoutAddDrilldownParams { overlays: () => Promise; } -export class OpenFlyoutAddDrilldown implements Action { +export class FlyoutCreateDrilldownAction implements Action { public readonly type = OPEN_FLYOUT_ADD_DRILLDOWN; public readonly id = OPEN_FLYOUT_ADD_DRILLDOWN; - public order = 100; + public order = 5; constructor(protected readonly params: OpenFlyoutAddDrilldownParams) {} public getDisplayName() { - return i18n.translate('xpack.drilldowns.panel.openFlyoutAddDrilldown.displayName', { - defaultMessage: 'Add drilldown', + return i18n.translate('xpack.drilldowns.FlyoutCreateDrilldownAction.displayName', { + defaultMessage: 'Create Drilldown', }); } public getIconType() { - return 'empty'; + return 'plusInCircle'; } - public async isCompatible({ embeddable }: ActionContext) { + public async isCompatible({ embeddable }: FlyoutCreateDrilldownActionContext) { return true; } - public async execute({ embeddable }: ActionContext) { + public async execute(context: FlyoutCreateDrilldownActionContext) { const overlays = await this.params.overlays(); - overlays.openFlyout(toMountPoint()); + const handle = overlays.openFlyout( + toMountPoint( handle.close()} />) + ); } } diff --git a/x-pack/plugins/drilldowns/public/actions/index.ts b/x-pack/plugins/drilldowns/public/actions/index.ts index c0ca7fac22049..ce235043b4ef6 100644 --- a/x-pack/plugins/drilldowns/public/actions/index.ts +++ b/x-pack/plugins/drilldowns/public/actions/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './open_flyout_add_drilldown'; +export * from './flyout_create_drilldown'; diff --git a/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/__examples__/drilldown_hello_bar.examples.tsx b/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/drilldown_hello_bar.story.tsx similarity index 91% rename from x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/__examples__/drilldown_hello_bar.examples.tsx rename to x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/drilldown_hello_bar.story.tsx index afa82f5e74c16..7a9e19342f27c 100644 --- a/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/__examples__/drilldown_hello_bar.examples.tsx +++ b/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/drilldown_hello_bar.story.tsx @@ -6,7 +6,7 @@ import * as React from 'react'; import { storiesOf } from '@storybook/react'; -import { DrilldownHelloBar } from '..'; +import { DrilldownHelloBar } from '.'; storiesOf('components/DrilldownHelloBar', module).add('default', () => { return ; diff --git a/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/drilldown_hello_bar.tsx b/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/drilldown_hello_bar.tsx new file mode 100644 index 0000000000000..1ef714f7b86e2 --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/drilldown_hello_bar.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; + +export interface DrilldownHelloBarProps { + docsLink?: string; +} + +/** + * @todo https://github.com/elastic/kibana/issues/55311 + */ +export const DrilldownHelloBar: React.FC = ({ docsLink }) => { + return ( +
+

+ Drilldowns provide the ability to define a new behavior when interacting with a panel. You + can add multiple options or simply override the default filtering behavior. +

+ View docs +
+ ); +}; diff --git a/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/index.tsx b/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/index.tsx index 895a100df3ac5..f28c8cfa3a059 100644 --- a/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/index.tsx +++ b/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/index.tsx @@ -4,24 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; - -export interface DrilldownHelloBarProps { - docsLink?: string; -} - -export const DrilldownHelloBar: React.FC = ({ docsLink }) => { - return ( -
-

- Drilldowns provide the ability to define a new behavior when interacting with a panel. You - can add multiple options or simply override the default filtering behavior. -

- View docs - -
- ); -}; +export * from './drilldown_hello_bar'; diff --git a/x-pack/plugins/drilldowns/public/components/drilldown_picker/__examples__/drilldown_picker.examples.tsx b/x-pack/plugins/drilldowns/public/components/drilldown_picker/drilldown_picker.story.tsx similarity index 91% rename from x-pack/plugins/drilldowns/public/components/drilldown_picker/__examples__/drilldown_picker.examples.tsx rename to x-pack/plugins/drilldowns/public/components/drilldown_picker/drilldown_picker.story.tsx index dfdd9627ab5cd..5627a5d6f4522 100644 --- a/x-pack/plugins/drilldowns/public/components/drilldown_picker/__examples__/drilldown_picker.examples.tsx +++ b/x-pack/plugins/drilldowns/public/components/drilldown_picker/drilldown_picker.story.tsx @@ -6,7 +6,7 @@ import * as React from 'react'; import { storiesOf } from '@storybook/react'; -import { DrilldownPicker } from '..'; +import { DrilldownPicker } from '.'; storiesOf('components/DrilldownPicker', module).add('default', () => { return ; diff --git a/x-pack/plugins/drilldowns/public/components/drilldown_picker/drilldown_picker.tsx b/x-pack/plugins/drilldowns/public/components/drilldown_picker/drilldown_picker.tsx new file mode 100644 index 0000000000000..3748fc666c81c --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/drilldown_picker/drilldown_picker.tsx @@ -0,0 +1,21 @@ +/* + * 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'; + +// eslint-disable-next-line +export interface DrilldownPickerProps {} + +export const DrilldownPicker: React.FC = () => { + return ( + + ); +}; diff --git a/x-pack/plugins/drilldowns/public/components/drilldown_picker/index.tsx b/x-pack/plugins/drilldowns/public/components/drilldown_picker/index.tsx index 3748fc666c81c..3be289fe6d46e 100644 --- a/x-pack/plugins/drilldowns/public/components/drilldown_picker/index.tsx +++ b/x-pack/plugins/drilldowns/public/components/drilldown_picker/index.tsx @@ -4,18 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; - -// eslint-disable-next-line -export interface DrilldownPickerProps {} - -export const DrilldownPicker: React.FC = () => { - return ( - - ); -}; +export * from './drilldown_picker'; diff --git a/x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/flyout_create_drilldown.story.tsx b/x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/flyout_create_drilldown.story.tsx new file mode 100644 index 0000000000000..4f024b7d9cd6a --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/flyout_create_drilldown.story.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* eslint-disable no-console */ + +import * as React from 'react'; +import { EuiFlyout } from '@elastic/eui'; +import { storiesOf } from '@storybook/react'; +import { FlyoutCreateDrilldown } from '.'; + +storiesOf('components/FlyoutCreateDrilldown', module) + .add('default', () => { + return ; + }) + .add('open in flyout', () => { + return ( + + + + ); + }); diff --git a/x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/flyout_create_drilldown.tsx b/x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/flyout_create_drilldown.tsx new file mode 100644 index 0000000000000..b45ac9197c7e0 --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/flyout_create_drilldown.tsx @@ -0,0 +1,34 @@ +/* + * 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 { EuiButton } from '@elastic/eui'; +import { FormCreateDrilldown } from '../form_create_drilldown'; +import { FlyoutFrame } from '../flyout_frame'; +import { txtCreateDrilldown } from './i18n'; +import { FlyoutCreateDrilldownActionContext } from '../../actions'; + +export interface FlyoutCreateDrilldownProps { + context: FlyoutCreateDrilldownActionContext; + onClose?: () => void; +} + +export const FlyoutCreateDrilldown: React.FC = ({ + context, + onClose, +}) => { + const footer = ( + {}} fill> + {txtCreateDrilldown} + + ); + + return ( + + + + ); +}; diff --git a/x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/i18n.ts b/x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/i18n.ts new file mode 100644 index 0000000000000..ceabc6d3a9aa5 --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/i18n.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const txtCreateDrilldown = i18n.translate( + 'xpack.drilldowns.components.FlyoutCreateDrilldown.CreateDrilldown', + { + defaultMessage: 'Create drilldown', + } +); diff --git a/x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/index.ts b/x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/index.ts new file mode 100644 index 0000000000000..ce235043b4ef6 --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/flyout_create_drilldown/index.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 * from './flyout_create_drilldown'; diff --git a/x-pack/plugins/drilldowns/public/components/flyout_frame/flyout_frame.story.tsx b/x-pack/plugins/drilldowns/public/components/flyout_frame/flyout_frame.story.tsx new file mode 100644 index 0000000000000..2715637f6392f --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/flyout_frame/flyout_frame.story.tsx @@ -0,0 +1,39 @@ +/* + * 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. + */ + +/* eslint-disable no-console */ + +import * as React from 'react'; +import { EuiFlyout, EuiButton } from '@elastic/eui'; +import { storiesOf } from '@storybook/react'; +import { FlyoutFrame } from '.'; + +storiesOf('components/FlyoutFrame', module) + .add('default', () => { + return test; + }) + .add('with title', () => { + return test; + }) + .add('with onClose', () => { + return console.log('onClose')}>test; + }) + .add('custom footer', () => { + return click me!}>test; + }) + .add('open in flyout', () => { + return ( + + Save} + onClose={() => console.log('onClose')} + > + test + + + ); + }); diff --git a/x-pack/plugins/drilldowns/public/components/flyout_frame/flyout_frame.test.tsx b/x-pack/plugins/drilldowns/public/components/flyout_frame/flyout_frame.test.tsx new file mode 100644 index 0000000000000..b5fb52fcf5c18 --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/flyout_frame/flyout_frame.test.tsx @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { render } from 'react-dom'; +import { render as renderTestingLibrary, fireEvent } from '@testing-library/react'; +import { FlyoutFrame } from '.'; + +describe('', () => { + test('renders without crashing', () => { + const div = document.createElement('div'); + render(, div); + }); + + describe('[title=]', () => { + test('renders title in

tag', () => { + const div = document.createElement('div'); + render(, div); + + const title = div.querySelector('h1'); + expect(title?.textContent).toBe('foobar'); + }); + + test('title can be any react node', () => { + const div = document.createElement('div'); + render( + + foo bar + + } + />, + div + ); + + const title = div.querySelector('h1'); + expect(title?.innerHTML).toBe('foo bar'); + }); + }); + + describe('[footer=]', () => { + test('if [footer=] prop not provided, does not render footer', () => { + const div = document.createElement('div'); + render(, div); + + const footer = div.querySelector('[data-test-subj="flyoutFooter"]'); + expect(footer).toBe(null); + }); + + test('can render anything in footer', () => { + const div = document.createElement('div'); + render( + + a b + + } + />, + div + ); + + const footer = div.querySelector('[data-test-subj="flyoutFooter"]'); + expect(footer?.innerHTML).toBe('a b'); + }); + }); + + describe('[onClose=]', () => { + test('does not render close button if "onClose" prop is missing', () => { + const div = document.createElement('div'); + render(, div); + + const closeButton = div.querySelector('[data-test-subj="flyoutCloseButton"]'); + expect(closeButton).toBe(null); + }); + + test('renders close button if "onClose" prop is provided', () => { + const div = document.createElement('div'); + render( {}} />, div); + + const closeButton = div.querySelector('[data-test-subj="flyoutCloseButton"]'); + expect(closeButton).not.toBe(null); + }); + + test('calls onClose prop when close button clicked', async () => { + const onClose = jest.fn(); + const el = renderTestingLibrary(); + + const closeButton = el.queryByText('Close'); + + expect(onClose).toHaveBeenCalledTimes(0); + + fireEvent.click(closeButton!); + + expect(onClose).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/x-pack/plugins/drilldowns/public/components/flyout_frame/flyout_frame.tsx b/x-pack/plugins/drilldowns/public/components/flyout_frame/flyout_frame.tsx new file mode 100644 index 0000000000000..2945cfd739482 --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/flyout_frame/flyout_frame.tsx @@ -0,0 +1,71 @@ +/* + * 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 { + EuiFlyoutHeader, + EuiTitle, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, +} from '@elastic/eui'; +import { txtClose } from './i18n'; + +export interface FlyoutFrameProps { + title?: React.ReactNode; + footer?: React.ReactNode; + onClose?: () => void; +} + +/** + * @todo This component can be moved to `kibana_react`. + */ +export const FlyoutFrame: React.FC = ({ + title = '', + footer, + onClose, + children, +}) => { + const headerFragment = title && ( + + +

{title}

+
+
+ ); + + const footerFragment = (onClose || footer) && ( + + + + {onClose && ( + + {txtClose} + + )} + + + {footer} + + + + ); + + return ( + <> + {headerFragment} + {children} + {footerFragment} + + ); +}; diff --git a/x-pack/plugins/drilldowns/public/components/form_create_drilldown/__examples__/form_create_drilldown.examples.tsx b/x-pack/plugins/drilldowns/public/components/flyout_frame/i18n.ts similarity index 51% rename from x-pack/plugins/drilldowns/public/components/form_create_drilldown/__examples__/form_create_drilldown.examples.tsx rename to x-pack/plugins/drilldowns/public/components/flyout_frame/i18n.ts index 34f6932b41dac..257d7d36dbee1 100644 --- a/x-pack/plugins/drilldowns/public/components/form_create_drilldown/__examples__/form_create_drilldown.examples.tsx +++ b/x-pack/plugins/drilldowns/public/components/flyout_frame/i18n.ts @@ -4,10 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as React from 'react'; -import { storiesOf } from '@storybook/react'; -import { FormCreateDrilldown } from '..'; +import { i18n } from '@kbn/i18n'; -storiesOf('components/FormCreateDrilldown', module).add('default', () => { - return ; +export const txtClose = i18n.translate('xpack.drilldowns.components.FlyoutFrame.Close', { + defaultMessage: 'Close', }); diff --git a/x-pack/plugins/drilldowns/public/components/flyout_frame/index.tsx b/x-pack/plugins/drilldowns/public/components/flyout_frame/index.tsx new file mode 100644 index 0000000000000..040b4b6b5e243 --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/flyout_frame/index.tsx @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export * from './flyout_frame'; diff --git a/x-pack/plugins/drilldowns/public/components/form_create_drilldown/form_create_drilldown.story.tsx b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/form_create_drilldown.story.tsx new file mode 100644 index 0000000000000..e7e1d67473e8c --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/form_create_drilldown.story.tsx @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/* eslint-disable no-console */ + +import * as React from 'react'; +import { EuiFlyout } from '@elastic/eui'; +import { storiesOf } from '@storybook/react'; +import { FormCreateDrilldown } from '.'; + +const DemoEditName: React.FC = () => { + const [name, setName] = React.useState(''); + + return ; +}; + +storiesOf('components/FormCreateDrilldown', module) + .add('default', () => { + return ; + }) + .add('[name=foobar]', () => { + return ; + }) + .add('can edit name', () => ) + .add('open in flyout', () => { + return ( + + + + ); + }); diff --git a/x-pack/plugins/drilldowns/public/components/form_create_drilldown/form_create_drilldown.test.tsx b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/form_create_drilldown.test.tsx new file mode 100644 index 0000000000000..6691966e47e64 --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/form_create_drilldown.test.tsx @@ -0,0 +1,68 @@ +/* + * 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 { render } from 'react-dom'; +import { FormCreateDrilldown } from '.'; +import { render as renderTestingLibrary, fireEvent } from '@testing-library/react'; +import { txtNameOfDrilldown } from './i18n'; + +describe('', () => { + test('renders without crashing', () => { + const div = document.createElement('div'); + render( {}} />, div); + }); + + describe('[name=]', () => { + test('if name not provided, uses to empty string', () => { + const div = document.createElement('div'); + + render(, div); + + const input = div.querySelector( + '[data-test-subj="dynamicActionNameInput"]' + ) as HTMLInputElement; + + expect(input?.value).toBe(''); + }); + + test('can set name input field value', () => { + const div = document.createElement('div'); + + render(, div); + + const input = div.querySelector( + '[data-test-subj="dynamicActionNameInput"]' + ) as HTMLInputElement; + + expect(input?.value).toBe('foo'); + + render(, div); + + expect(input?.value).toBe('bar'); + }); + + test('fires onNameChange callback on name change', () => { + const onNameChange = jest.fn(); + const utils = renderTestingLibrary( + + ); + const input = utils.getByLabelText(txtNameOfDrilldown); + + expect(onNameChange).toHaveBeenCalledTimes(0); + + fireEvent.change(input, { target: { value: 'qux' } }); + + expect(onNameChange).toHaveBeenCalledTimes(1); + expect(onNameChange).toHaveBeenCalledWith('qux'); + + fireEvent.change(input, { target: { value: 'quxx' } }); + + expect(onNameChange).toHaveBeenCalledTimes(2); + expect(onNameChange).toHaveBeenCalledWith('quxx'); + }); + }); +}); diff --git a/x-pack/plugins/drilldowns/public/components/form_create_drilldown/form_create_drilldown.tsx b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/form_create_drilldown.tsx new file mode 100644 index 0000000000000..4422de604092b --- /dev/null +++ b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/form_create_drilldown.tsx @@ -0,0 +1,52 @@ +/* + * 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 { EuiForm, EuiFormRow, EuiFieldText } from '@elastic/eui'; +import { DrilldownHelloBar } from '../drilldown_hello_bar'; +import { txtNameOfDrilldown, txtUntitledDrilldown, txtDrilldownAction } from './i18n'; +import { DrilldownPicker } from '../drilldown_picker'; + +const noop = () => {}; + +export interface FormCreateDrilldownProps { + name?: string; + onNameChange?: (name: string) => void; +} + +export const FormCreateDrilldown: React.FC = ({ + name = '', + onNameChange = noop, +}) => { + const nameFragment = ( + + onNameChange(event.target.value)} + data-test-subj="dynamicActionNameInput" + /> + + ); + + const triggerPicker =
Trigger Picker will be here
; + const actionPicker = ( + + + + ); + + return ( + <> + + {nameFragment} + {triggerPicker} + {actionPicker} + + ); +}; diff --git a/x-pack/plugins/drilldowns/public/components/form_create_drilldown/i18n.ts b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/i18n.ts index 922131ba4b901..4c0e287935edd 100644 --- a/x-pack/plugins/drilldowns/public/components/form_create_drilldown/i18n.ts +++ b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/i18n.ts @@ -7,21 +7,21 @@ import { i18n } from '@kbn/i18n'; export const txtNameOfDrilldown = i18n.translate( - 'xpack.drilldowns.components.form_create_drilldown.nameOfDrilldown', + 'xpack.drilldowns.components.FormCreateDrilldown.nameOfDrilldown', { defaultMessage: 'Name of drilldown', } ); export const txtUntitledDrilldown = i18n.translate( - 'xpack.drilldowns.components.form_create_drilldown.untitledDrilldown', + 'xpack.drilldowns.components.FormCreateDrilldown.untitledDrilldown', { defaultMessage: 'Untitled drilldown', } ); export const txtDrilldownAction = i18n.translate( - 'xpack.drilldowns.components.form_create_drilldown.drilldownAction', + 'xpack.drilldowns.components.FormCreateDrilldown.drilldownAction', { defaultMessage: 'Drilldown action', } diff --git a/x-pack/plugins/drilldowns/public/components/form_create_drilldown/index.tsx b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/index.tsx index 40cd4cf2b210b..c2c5a7e435b39 100644 --- a/x-pack/plugins/drilldowns/public/components/form_create_drilldown/index.tsx +++ b/x-pack/plugins/drilldowns/public/components/form_create_drilldown/index.tsx @@ -4,27 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; -import { EuiForm, EuiFormRow, EuiFieldText } from '@elastic/eui'; -import { DrilldownHelloBar } from '../drilldown_hello_bar'; -import { txtNameOfDrilldown, txtUntitledDrilldown, txtDrilldownAction } from './i18n'; -import { DrilldownPicker } from '../drilldown_picker'; - -// eslint-disable-next-line -export interface FormCreateDrilldownProps {} - -export const FormCreateDrilldown: React.FC = () => { - return ( -
- - - - - - - - - -
- ); -}; +export * from './form_create_drilldown'; diff --git a/x-pack/plugins/drilldowns/public/service/drilldown_service.ts b/x-pack/plugins/drilldowns/public/service/drilldown_service.ts index f22f452181648..b1310ba003ff7 100644 --- a/x-pack/plugins/drilldowns/public/service/drilldown_service.ts +++ b/x-pack/plugins/drilldowns/public/service/drilldown_service.ts @@ -5,17 +5,17 @@ */ import { CoreSetup } from 'src/core/public'; -import { OpenFlyoutAddDrilldown } from '../actions/open_flyout_add_drilldown'; +import { FlyoutCreateDrilldownAction } from '../actions'; import { DrilldownsSetupDependencies } from '../plugin'; export class DrilldownService { bootstrap(core: CoreSetup, { uiActions }: DrilldownsSetupDependencies) { - const actionOpenFlyoutAddDrilldown = new OpenFlyoutAddDrilldown({ + const actionFlyoutCreateDrilldown = new FlyoutCreateDrilldownAction({ overlays: async () => (await core.getStartServices())[0].overlays, }); - uiActions.registerAction(actionOpenFlyoutAddDrilldown); - uiActions.attachAction('CONTEXT_MENU_TRIGGER', actionOpenFlyoutAddDrilldown.id); + uiActions.registerAction(actionFlyoutCreateDrilldown); + uiActions.attachAction('CONTEXT_MENU_TRIGGER', actionFlyoutCreateDrilldown.id); } /** diff --git a/x-pack/plugins/drilldowns/scripts/storybook.js b/x-pack/plugins/drilldowns/scripts/storybook.js index 9b0f57746e584..2bfd0eb1a8f19 100644 --- a/x-pack/plugins/drilldowns/scripts/storybook.js +++ b/x-pack/plugins/drilldowns/scripts/storybook.js @@ -9,5 +9,5 @@ import { join } from 'path'; // eslint-disable-next-line require('@kbn/storybook').runStorybookCli({ name: 'drilldowns', - storyGlobs: [join(__dirname, '..', 'public', 'components', '**', '*.examples.tsx')], + storyGlobs: [join(__dirname, '..', 'public', 'components', '**', '*.story.tsx')], }); From fac57c1cca66dc3aeccb535ccf99f5dba7b76535 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Tue, 25 Feb 2020 18:25:11 +0100 Subject: [PATCH 065/123] [Visualize] Improve linked saved search functional test (#58339) * Remove redundant sleep * convert to TypeScript --- ..._linked_saved_searches.js => _linked_saved_searches.ts} | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) rename test/functional/apps/visualize/{_linked_saved_searches.js => _linked_saved_searches.ts} (95%) diff --git a/test/functional/apps/visualize/_linked_saved_searches.js b/test/functional/apps/visualize/_linked_saved_searches.ts similarity index 95% rename from test/functional/apps/visualize/_linked_saved_searches.js rename to test/functional/apps/visualize/_linked_saved_searches.ts index 37ec3f06f2ecd..345987a803394 100644 --- a/test/functional/apps/visualize/_linked_saved_searches.js +++ b/test/functional/apps/visualize/_linked_saved_searches.ts @@ -18,8 +18,9 @@ */ import expect from '@kbn/expect'; - -export default function({ getService, getPageObjects }) { +import { FtrProviderContext } from '../../ftr_provider_context'; +// eslint-disable-next-line import/no-default-export +export default function({ getService, getPageObjects }: FtrProviderContext) { const filterBar = getService('filterBar'); const retry = getService('retry'); const PageObjects = getPageObjects([ @@ -40,8 +41,6 @@ export default function({ getService, getPageObjects }) { await filterBar.addFilter('extension.raw', 'is', 'jpg'); await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.saveSearch(savedSearchName); - // TODO: Remove this once https://github.com/elastic/kibana/issues/19750 is properly resolved - await PageObjects.common.sleep(500); }); it('should create a visualization from a saved search', async () => { From 93556a9bdddc671cabe218973b86ee8d7ecb5273 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 25 Feb 2020 18:31:24 +0100 Subject: [PATCH 066/123] Visualizations plugin np_ready (#57983) Partially addresses #50897 updates visualizations plugin makes visualizations/saved_visualizations np_ready makes visualizations/embeddable np_ready remove DefaultVisEditor dependency from visualizations import AggConfigs directly instead of ui/public Clean up imports from root. use relative imports Remove bind directive import --- src/legacy/core_plugins/data/public/index.ts | 2 + .../public/visualize/kibana_services.ts | 2 + .../kibana/public/visualize/legacy_imports.ts | 3 +- .../np_ready/editor/visualization_editor.js | 2 +- .../kibana/public/visualize/plugin.ts | 4 +- .../public/default_editor.tsx | 6 +- .../public/default_editor_controller.tsx | 2 +- .../public/embeddable/query_geohash_bounds.ts | 103 ------------------ .../visualizations/public/index.scss | 2 - .../visualizations/public/legacy_imports.ts | 8 +- .../public/np_ready/kibana.json | 5 +- .../public/np_ready/public/_index.scss | 1 + .../public}/embeddable/_embeddables.scss | 0 .../public}/embeddable/_index.scss | 0 .../embeddable/_visualize_lab_disabled.scss | 0 .../public}/embeddable/constants.ts | 0 .../embeddable/disabled_lab_embeddable.tsx | 2 +- .../embeddable/disabled_lab_visualization.tsx | 0 .../public}/embeddable/get_index_pattern.ts | 6 +- .../{ => np_ready/public}/embeddable/index.ts | 1 + .../embeddable/visualize_embeddable.ts | 47 ++++---- .../visualize_embeddable_factory.tsx | 37 +++---- .../expressions/visualization_function.ts | 7 +- .../public/np_ready/public/index.ts | 16 ++- .../public/np_ready/public/legacy.ts | 4 +- .../__tests__/vis_types/base_vis_type.js | 2 +- .../__tests__/vis_types/react_vis_type.js | 2 +- .../public/legacy/build_pipeline.test.ts | 5 - .../np_ready/public/legacy/build_pipeline.ts | 16 +-- .../public/np_ready/public/mocks.ts | 7 +- .../public/np_ready/public/plugin.ts | 62 ++++++----- .../saved_visualizations/_saved_vis.ts | 16 ++- .../find_list_items.test.ts} | 67 +++++++----- .../saved_visualizations/find_list_items.ts} | 33 ++++-- .../public}/saved_visualizations/index.ts | 0 .../saved_visualization_references.test.ts | 10 +- .../saved_visualization_references.ts | 4 +- .../saved_visualizations.ts | 11 +- .../public/np_ready/public/services.ts | 23 +++- .../public/np_ready/public/types.ts | 38 +++++++ .../public/np_ready/public/vis.ts | 2 +- .../public/np_ready/public/vis_impl.d.ts | 2 +- .../{types => vis_types}/base_vis_type.js | 4 +- .../public/{types => vis_types}/index.ts | 0 .../{types => vis_types}/react_vis_type.js | 0 .../{types => vis_types}/types_service.ts | 0 .../vis_type_alias_registry.ts | 2 +- .../public/wizard/new_vis_modal.test.tsx | 4 +- .../np_ready/public/wizard/new_vis_modal.tsx | 4 +- .../search_selection/search_selection.tsx | 4 +- .../wizard/type_selection/new_vis_help.tsx | 2 +- .../wizard/type_selection/type_selection.tsx | 2 +- .../save_modal/saved_object_save_modal.tsx | 6 +- .../expression_types/embeddable_types.ts | 2 +- .../functions/common/saved_visualization.ts | 2 +- .../embeddable_input_to_expression.test.ts | 1 + .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 58 files changed, 279 insertions(+), 316 deletions(-) delete mode 100644 src/legacy/core_plugins/visualizations/public/embeddable/query_geohash_bounds.ts rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/embeddable/_embeddables.scss (100%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/embeddable/_index.scss (100%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/embeddable/_visualize_lab_disabled.scss (100%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/embeddable/constants.ts (100%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/embeddable/disabled_lab_embeddable.tsx (94%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/embeddable/disabled_lab_visualization.tsx (100%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/embeddable/get_index_pattern.ts (90%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/embeddable/index.ts (92%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/embeddable/visualize_embeddable.ts (90%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/embeddable/visualize_embeddable_factory.tsx (85%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/saved_visualizations/_saved_vis.ts (90%) rename src/legacy/core_plugins/visualizations/public/{saved_visualizations/find_list_items.test.js => np_ready/public/saved_visualizations/find_list_items.test.ts} (77%) rename src/legacy/core_plugins/visualizations/public/{saved_visualizations/find_list_items.js => np_ready/public/saved_visualizations/find_list_items.ts} (64%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/saved_visualizations/index.ts (100%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/saved_visualizations/saved_visualization_references.test.ts (96%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/saved_visualizations/saved_visualization_references.ts (95%) rename src/legacy/core_plugins/visualizations/public/{ => np_ready/public}/saved_visualizations/saved_visualizations.ts (91%) create mode 100644 src/legacy/core_plugins/visualizations/public/np_ready/public/types.ts rename src/legacy/core_plugins/visualizations/public/np_ready/public/{types => vis_types}/base_vis_type.js (95%) rename src/legacy/core_plugins/visualizations/public/np_ready/public/{types => vis_types}/index.ts (100%) rename src/legacy/core_plugins/visualizations/public/np_ready/public/{types => vis_types}/react_vis_type.js (100%) rename src/legacy/core_plugins/visualizations/public/np_ready/public/{types => vis_types}/types_service.ts (100%) rename src/legacy/core_plugins/visualizations/public/np_ready/public/{types => vis_types}/vis_type_alias_registry.ts (97%) diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts index ce46f534141f4..8cde5d0a1fc11 100644 --- a/src/legacy/core_plugins/data/public/index.ts +++ b/src/legacy/core_plugins/data/public/index.ts @@ -54,6 +54,7 @@ export * from '../common'; export { FilterStateManager } from './filter/filter_manager'; export { // agg_types TODO need to group these under a namespace or prefix + AggConfigs, AggParamType, AggTypeFilters, // TODO convert to interface aggTypeFilters, @@ -66,6 +67,7 @@ export { convertIPRangeToString, intervalOptions, // only used in Discover isDateHistogramBucketAggConfig, + setBounds, isStringType, isType, isValidInterval, diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts index 096877d5824c4..cfd12b3283459 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts @@ -36,6 +36,7 @@ import { VisualizationsStart } from '../../../visualizations/public'; import { SavedVisualizations } from './np_ready/types'; import { UsageCollectionSetup } from '../../../../../plugins/usage_collection/public'; import { KibanaLegacyStart } from '../../../../../plugins/kibana_legacy/public'; +import { DefaultEditorController } from '../../../vis_default_editor/public'; export interface VisualizeKibanaServices { pluginInitializerContext: PluginInitializerContext; @@ -60,6 +61,7 @@ export interface VisualizeKibanaServices { usageCollection?: UsageCollectionSetup; I18nContext: I18nStart['Context']; setActiveUrl: (newUrl: string) => void; + DefaultVisualizationEditor: typeof DefaultEditorController; } let services: VisualizeKibanaServices | null = null; diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts index 8b1bb0fda8c84..d9565938c838d 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts @@ -43,8 +43,7 @@ export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url'; export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url'; export { wrapInI18nContext } from 'ui/i18n'; export { DashboardConstants } from '../dashboard/np_ready/dashboard_constants'; -export { VisSavedObject } from '../../../visualizations/public/embeddable/visualize_embeddable'; -export { VISUALIZE_EMBEDDABLE_TYPE } from '../../../visualizations/public/embeddable'; +export { VisSavedObject, VISUALIZE_EMBEDDABLE_TYPE } from '../../../visualizations/public/'; export { configureAppAngularModule, ensureDefaultIndexPattern, diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization_editor.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization_editor.js index c40a10115ae4e..65c25b8cf705d 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization_editor.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization_editor.js @@ -30,7 +30,7 @@ export function initVisEditorDirective(app, deps) { appState: '=', }, link: function($scope, element) { - const Editor = $scope.savedObj.vis.type.editor; + const Editor = $scope.savedObj.vis.type.editor || deps.DefaultVisualizationEditor; const editor = new Editor(element[0], $scope.savedObj); $scope.renderFunction = () => { diff --git a/src/legacy/core_plugins/kibana/public/visualize/plugin.ts b/src/legacy/core_plugins/kibana/public/visualize/plugin.ts index 22804685db3cc..9f2283d29c203 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/plugin.ts @@ -50,6 +50,7 @@ import { HomePublicPluginSetup, } from '../../../../../plugins/home/public'; import { UsageCollectionSetup } from '../../../../../plugins/usage_collection/public'; +import { DefaultEditorController } from '../../../vis_default_editor/public'; export interface VisualizePluginStartDependencies { data: DataPublicPluginStart; @@ -139,7 +140,7 @@ export class VisualizePlugin implements Plugin { localStorage: new Storage(localStorage), navigation, savedObjectsClient, - savedVisualizations: visualizations.getSavedVisualizationsLoader(), + savedVisualizations: visualizations.savedVisualizationsLoader, savedQueryService: dataStart.query.savedQueries, share, toastNotifications: coreStart.notifications.toasts, @@ -150,6 +151,7 @@ export class VisualizePlugin implements Plugin { usageCollection, I18nContext: coreStart.i18n.Context, setActiveUrl, + DefaultVisualizationEditor: DefaultEditorController, }; setServices(deps); diff --git a/src/legacy/core_plugins/vis_default_editor/public/default_editor.tsx b/src/legacy/core_plugins/vis_default_editor/public/default_editor.tsx index 32ea71c0bc005..7eee54006f684 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/default_editor.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/default_editor.tsx @@ -20,8 +20,10 @@ import React, { useEffect, useRef, useState, useCallback } from 'react'; import { EditorRenderProps } from '../../kibana/public/visualize/np_ready/types'; -import { VisualizeEmbeddable } from '../../visualizations/public/embeddable'; -import { VisualizeEmbeddableFactory } from '../../visualizations/public/embeddable/visualize_embeddable_factory'; +import { + VisualizeEmbeddableContract as VisualizeEmbeddable, + VisualizeEmbeddableFactoryContract as VisualizeEmbeddableFactory, +} from '../../visualizations/public/'; import { PanelsContainer, Panel } from '../../../../plugins/kibana_react/public'; import './vis_type_agg_filter'; diff --git a/src/legacy/core_plugins/vis_default_editor/public/default_editor_controller.tsx b/src/legacy/core_plugins/vis_default_editor/public/default_editor_controller.tsx index d3090d277aef9..db910604eddd1 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/default_editor_controller.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/default_editor_controller.tsx @@ -23,7 +23,7 @@ import { i18n } from '@kbn/i18n'; import { I18nProvider } from '@kbn/i18n/react'; import { EditorRenderProps } from 'src/legacy/core_plugins/kibana/public/visualize/np_ready/types'; -import { VisSavedObject } from 'src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable'; +import { VisSavedObject } from 'src/legacy/core_plugins/visualizations/public/'; import { Storage } from '../../../../plugins/kibana_utils/public'; import { KibanaContextProvider } from '../../../../plugins/kibana_react/public'; import { DefaultEditor } from './default_editor'; diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/query_geohash_bounds.ts b/src/legacy/core_plugins/visualizations/public/embeddable/query_geohash_bounds.ts deleted file mode 100644 index f37bc858efab0..0000000000000 --- a/src/legacy/core_plugins/visualizations/public/embeddable/query_geohash_bounds.ts +++ /dev/null @@ -1,103 +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 { i18n } from '@kbn/i18n'; -import { get } from 'lodash'; -import { toastNotifications } from 'ui/notify'; - -import { IAggConfig } from 'ui/agg_types'; -import { timefilter } from 'ui/timefilter'; -import { Vis } from '../np_ready/public'; -import { Filter, Query, SearchSource, ISearchSource } from '../../../../../plugins/data/public'; - -interface QueryGeohashBoundsParams { - filters?: Filter[]; - query?: Query; - searchSource?: ISearchSource; -} - -/** - * Coordinate map visualization needs to be able to query for the latest geohash - * bounds when a user clicks the "fit to data" map icon, which requires knowing - * about global filters & queries. This logic has been extracted here so we can - * keep `searchSource` out of the vis, but ultimately we need to design a - * long-term solution for situations like this. - * - * TODO: Remove this as a part of elastic/kibana#30593 - */ -export async function queryGeohashBounds(vis: Vis, params: QueryGeohashBoundsParams) { - const agg = vis.getAggConfig().aggs.find((a: IAggConfig) => { - return get(a, 'type.dslName') === 'geohash_grid'; - }); - - if (agg) { - const searchSource = params.searchSource - ? params.searchSource.createChild() - : new SearchSource(); - searchSource.setField('size', 0); - searchSource.setField('aggs', () => { - const geoBoundsAgg = vis.getAggConfig().createAggConfig( - { - type: 'geo_bounds', - enabled: true, - params: { - field: agg.getField(), - }, - schema: 'metric', - }, - { - addToAggConfigs: false, - } - ); - return { - '1': geoBoundsAgg.toDsl(), - }; - }); - - const { filters, query } = params; - if (filters) { - searchSource.setField('filter', () => { - const activeFilters = [...filters]; - const indexPattern = agg.getIndexPattern(); - const useTimeFilter = !!indexPattern.timeFieldName; - if (useTimeFilter) { - const filter = timefilter.createFilter(indexPattern); - if (filter) activeFilters.push((filter as any) as Filter); - } - return activeFilters; - }); - } - if (query) { - searchSource.setField('query', query); - } - - try { - const esResp = await searchSource.fetch(); - return get(esResp, 'aggregations.1.bounds'); - } catch (error) { - toastNotifications.addDanger({ - title: i18n.translate('visualizations.queryGeohashBounds.unableToGetBoundErrorTitle', { - defaultMessage: 'Unable to get bounds', - }), - text: `${error.message}`, - }); - return; - } - } -} diff --git a/src/legacy/core_plugins/visualizations/public/index.scss b/src/legacy/core_plugins/visualizations/public/index.scss index 748945eabd331..238f58fbfa295 100644 --- a/src/legacy/core_plugins/visualizations/public/index.scss +++ b/src/legacy/core_plugins/visualizations/public/index.scss @@ -1,4 +1,2 @@ @import 'src/legacy/ui/public/styles/styling_constants'; - -@import './embeddable/index'; @import './np_ready/public/index'; diff --git a/src/legacy/core_plugins/visualizations/public/legacy_imports.ts b/src/legacy/core_plugins/visualizations/public/legacy_imports.ts index 5cff588d951b0..223c130df3505 100644 --- a/src/legacy/core_plugins/visualizations/public/legacy_imports.ts +++ b/src/legacy/core_plugins/visualizations/public/legacy_imports.ts @@ -24,9 +24,5 @@ export { IAggConfigs, isDateHistogramBucketAggConfig, setBounds, -} from '../../../ui/public/agg_types'; -export { createFormat } from '../../../ui/public/visualize/loader/pipeline_helpers/utilities'; -export { I18nContext } from '../../../ui/public/i18n'; -import chrome from '../../../ui/public/chrome'; -export { chrome as legacyChrome }; -import '../../../ui/public/directives/bind'; +} from '../../data/public'; +export { createSavedSearchesLoader } from '../../kibana/public/discover/saved_searches/'; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/kibana.json b/src/legacy/core_plugins/visualizations/public/np_ready/kibana.json index 888edde44a261..d4f9bd327d6ac 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/kibana.json +++ b/src/legacy/core_plugins/visualizations/public/np_ready/kibana.json @@ -3,8 +3,5 @@ "version": "kibana", "server": false, "ui": true, - "requiredPlugins": [ - "data", - "search" - ] + "requiredPlugins": ["data", "search", "expressions", "uiActions"] } diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/_index.scss b/src/legacy/core_plugins/visualizations/public/np_ready/public/_index.scss index d87b6b004a511..eada763b63c4d 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/_index.scss +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/_index.scss @@ -1 +1,2 @@ @import 'wizard/index'; +@import 'embeddable/index'; diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/_embeddables.scss b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/_embeddables.scss similarity index 100% rename from src/legacy/core_plugins/visualizations/public/embeddable/_embeddables.scss rename to src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/_embeddables.scss diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/_index.scss b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/_index.scss similarity index 100% rename from src/legacy/core_plugins/visualizations/public/embeddable/_index.scss rename to src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/_index.scss diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/_visualize_lab_disabled.scss b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/_visualize_lab_disabled.scss similarity index 100% rename from src/legacy/core_plugins/visualizations/public/embeddable/_visualize_lab_disabled.scss rename to src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/_visualize_lab_disabled.scss diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/constants.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/constants.ts similarity index 100% rename from src/legacy/core_plugins/visualizations/public/embeddable/constants.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/constants.ts diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/disabled_lab_embeddable.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/disabled_lab_embeddable.tsx similarity index 94% rename from src/legacy/core_plugins/visualizations/public/embeddable/disabled_lab_embeddable.tsx rename to src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/disabled_lab_embeddable.tsx index f9dfd5d2b98f4..fbb2eba3afe79 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/disabled_lab_embeddable.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/disabled_lab_embeddable.tsx @@ -19,7 +19,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { Embeddable, EmbeddableOutput } from '../../../../../plugins/embeddable/public'; +import { Embeddable, EmbeddableOutput } from '../../../../../../../plugins/embeddable/public'; import { DisabledLabVisualization } from './disabled_lab_visualization'; import { VisualizeInput } from './visualize_embeddable'; diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/disabled_lab_visualization.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/disabled_lab_visualization.tsx similarity index 100% rename from src/legacy/core_plugins/visualizations/public/embeddable/disabled_lab_visualization.tsx rename to src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/disabled_lab_visualization.tsx diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/get_index_pattern.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/get_index_pattern.ts similarity index 90% rename from src/legacy/core_plugins/visualizations/public/embeddable/get_index_pattern.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/get_index_pattern.ts index cfb2960cfbb7c..51d839275fd27 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/get_index_pattern.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/get_index_pattern.ts @@ -17,13 +17,13 @@ * under the License. */ -import { VisSavedObject } from './visualize_embeddable'; +import { VisSavedObject } from '../types'; import { indexPatterns, IIndexPattern, IndexPatternAttributes, -} from '../../../../../plugins/data/public'; -import { getUISettings, getSavedObjects } from '../np_ready/public/services'; +} from '../../../../../../../plugins/data/public'; +import { getUISettings, getSavedObjects } from '../services'; export async function getIndexPattern( savedVis: VisSavedObject diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/index.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/index.ts similarity index 92% rename from src/legacy/core_plugins/visualizations/public/embeddable/index.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/index.ts index d7c0205891ec5..a1cd31eebef20 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/index.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/index.ts @@ -18,4 +18,5 @@ */ export { DisabledLabEmbeddable } from './disabled_lab_embeddable'; export { VisualizeEmbeddable, VisualizeInput } from './visualize_embeddable'; +export { VisualizeEmbeddableFactory } from './visualize_embeddable_factory'; export { VISUALIZE_EMBEDDABLE_TYPE } from './constants'; diff --git a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable.ts similarity index 90% rename from src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable.ts index 32bbae13b79b8..2537caa01cd46 100644 --- a/src/legacy/core_plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable.ts @@ -18,13 +18,8 @@ */ import _, { get } from 'lodash'; -import { PersistedState } from 'ui/persisted_state'; import { Subscription } from 'rxjs'; import * as Rx from 'rxjs'; -import { buildPipeline } from 'ui/visualize/loader/pipeline_helpers'; -import { npStart } from 'ui/new_platform'; -import { IExpressionLoaderParams } from 'src/plugins/expressions/public'; -import { EmbeddableVisTriggerContext } from 'src/plugins/embeddable/public'; import { VISUALIZE_EMBEDDABLE_TYPE } from './constants'; import { IIndexPattern, @@ -32,9 +27,8 @@ import { Query, esFilters, Filter, - ISearchSource, TimefilterContract, -} from '../../../../../plugins/data/public'; +} from '../../../../../../../plugins/data/public'; import { EmbeddableInput, EmbeddableOutput, @@ -42,27 +36,21 @@ import { Container, selectRangeTrigger, valueClickTrigger, -} from '../../../../../plugins/embeddable/public'; -import { dispatchRenderComplete } from '../../../../../plugins/kibana_utils/public'; -import { SavedObject } from '../../../../../plugins/saved_objects/public'; -import { SavedSearch } from '../../../kibana/public/discover/np_ready/types'; -import { Vis } from '../np_ready/public'; + EmbeddableVisTriggerContext, +} from '../../../../../../../plugins/embeddable/public'; +import { dispatchRenderComplete } from '../../../../../../../plugins/kibana_utils/public'; +import { + IExpressionLoaderParams, + ExpressionsStart, +} from '../../../../../../../plugins/expressions/public'; +import { buildPipeline } from '../legacy/build_pipeline'; +import { Vis } from '../vis'; +import { getExpressions, getUiActions } from '../services'; +import { PersistedState } from '../../../legacy_imports'; +import { VisSavedObject } from '../types'; const getKeys = (o: T): Array => Object.keys(o) as Array; -export interface VisSavedObject extends SavedObject { - vis: Vis; - description?: string; - searchSource: ISearchSource; - title: string; - uiStateJSON?: string; - destroy: () => void; - savedSearchRefName?: string; - savedSearchId?: string; - savedSearch?: SavedSearch; - visState: any; -} - export interface VisualizeEmbeddableConfiguration { savedVisualization: VisSavedObject; indexPatterns?: IIndexPattern[]; @@ -90,7 +78,7 @@ export interface VisualizeOutput extends EmbeddableOutput { visTypeName: string; } -type ExpressionLoader = InstanceType; +type ExpressionLoader = InstanceType; export class VisualizeEmbeddable extends Embeddable { private handler?: ExpressionLoader; @@ -281,7 +269,8 @@ export class VisualizeEmbeddable extends Embeddable { @@ -309,7 +298,9 @@ export class VisualizeEmbeddable extends Embeddable { public readonly type = VISUALIZE_EMBEDDABLE_TYPE; - constructor( - private timefilter: TimefilterContract, - private getSavedVisualizationsLoader: () => SavedVisualizations - ) { + constructor() { super({ savedObjectMetaData: { name: i18n.translate('visualizations.savedObjectName', { defaultMessage: 'Visualization' }), @@ -101,7 +98,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory< input: Partial & { id: string }, parent?: Container ): Promise { - const savedVisualizations = this.getSavedVisualizationsLoader(); + const savedVisualizations = getSavedVisualizationsLoader(); try { const visId = savedObject.id as string; @@ -118,7 +115,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory< const indexPattern = await getIndexPattern(savedObject); const indexPatterns = indexPattern ? [indexPattern] : []; return new VisualizeEmbeddable( - this.timefilter, + getTimeFilter(), { savedVisualization: savedObject, indexPatterns, @@ -141,7 +138,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory< input: Partial & { id: string }, parent?: Container ): Promise { - const savedVisualizations = this.getSavedVisualizationsLoader(); + const savedVisualizations = getSavedVisualizationsLoader(); try { const savedObject = await savedVisualizations.get(savedObjectId); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/visualization_function.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/visualization_function.ts index f1c1677a60f26..4ac0931c5d865 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/visualization_function.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/visualization_function.ts @@ -19,8 +19,11 @@ import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { VisResponseValue } from 'src/plugins/visualizations/public'; -import { ExpressionFunctionDefinition, Render } from 'src/plugins/expressions/public'; +import { VisResponseValue } from '../../../../../../../plugins/visualizations/public'; +import { + ExpressionFunctionDefinition, + Render, +} from '../../../../../../../plugins/expressions/public'; import { PersistedState } from '../../../legacy_imports'; import { getTypes, getIndexPatterns, getFilterManager } from '../services'; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts index 3c4a1c1449d47..34ffb698e5f8c 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts @@ -29,22 +29,28 @@ * either types, or static code. */ -import { PluginInitializerContext } from 'src/core/public'; +import { PublicContract } from '@kbn/utility-types'; +import { PluginInitializerContext } from '../../../../../../core/public'; import { VisualizationsPlugin, VisualizationsSetup, VisualizationsStart } from './plugin'; /** @public */ export { VisualizationsSetup, VisualizationsStart }; /** @public types */ -export { VisTypeAlias, VisType } from './types'; +export { VisTypeAlias, VisType } from './vis_types'; +export { VisSavedObject } from './types'; +export { Vis, VisParams, VisState } from './vis'; +import { VisualizeEmbeddableFactory, VisualizeEmbeddable } from './embeddable'; +export type VisualizeEmbeddableFactoryContract = PublicContract; +export type VisualizeEmbeddableContract = PublicContract; export function plugin(initializerContext: PluginInitializerContext) { return new VisualizationsPlugin(initializerContext); } /** @public static code */ -export { Vis, VisParams, VisState } from './vis'; -export { TypesService } from './types/types_service'; +export { TypesService } from './vis_types/types_service'; +export { VISUALIZE_EMBEDDABLE_TYPE, VisualizeInput } from './embeddable'; export { Status } from './legacy/update_status'; export { buildPipeline, buildVislibDimensions, SchemaConfig } from './legacy/build_pipeline'; @@ -52,4 +58,4 @@ export { buildPipeline, buildVislibDimensions, SchemaConfig } from './legacy/bui // @ts-ignore export { updateOldState } from './legacy/vis_update_state'; export { calculateObjectHash } from './legacy/calculate_object_hash'; -export { createSavedVisLoader } from '../../saved_visualizations/saved_visualizations'; +export { createSavedVisLoader } from './saved_visualizations/saved_visualizations'; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy.ts index 41b23b276e88d..57c686b6e9cb0 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy.ts @@ -17,12 +17,12 @@ * under the License. */ -import { PluginInitializerContext } from 'src/core/public'; - /* eslint-disable @kbn/eslint/no-restricted-paths */ import { npSetup, npStart } from 'ui/new_platform'; /* eslint-enable @kbn/eslint/no-restricted-paths */ +import { PluginInitializerContext } from '../../../../../../core/public'; + import { plugin } from '.'; const pluginInstance = plugin({} as PluginInitializerContext); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/vis_types/base_vis_type.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/vis_types/base_vis_type.js index b8aa33d0a5abe..9c1dfd9780255 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/vis_types/base_vis_type.js +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/vis_types/base_vis_type.js @@ -19,7 +19,7 @@ import expect from '@kbn/expect'; import ngMock from 'ng_mock'; -import { BaseVisType } from '../../../types/base_vis_type'; +import { BaseVisType } from '../../../vis_types/base_vis_type'; describe('Base Vis Type', function() { beforeEach(ngMock.module('kibana')); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/vis_types/react_vis_type.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/vis_types/react_vis_type.js index c85557ea1b0b0..2474a58870424 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/vis_types/react_vis_type.js +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__tests__/vis_types/react_vis_type.js @@ -19,7 +19,7 @@ import expect from '@kbn/expect'; import ngMock from 'ng_mock'; -import { ReactVisType } from '../../../types/react_vis_type'; +import { ReactVisType } from '../../../vis_types/react_vis_type'; describe('React Vis Type', function() { const visConfig = { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts index f73dc3e19d0ef..1adf6fd23f5a5 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.test.ts @@ -31,11 +31,6 @@ import { IAggConfig } from '../../../legacy_imports'; import { searchSourceMock } from '../../../legacy_mocks'; jest.mock('ui/new_platform'); -jest.mock('ui/agg_types', () => ({ - setBounds: () => {}, - dateHistogramBucketAgg: () => {}, - isDateHistogramBucketAggConfig: () => true, -})); describe('visualize loader pipeline helpers: build pipeline', () => { describe('prepareJson', () => { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts index 025eef834ca86..155213b4103b0 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts @@ -18,17 +18,11 @@ */ import { cloneDeep, get } from 'lodash'; -// @ts-ignore import moment from 'moment'; -import { SerializedFieldFormat } from 'src/plugins/expressions/public'; -import { ISearchSource } from 'src/plugins/data/public'; -import { - IAggConfig, - setBounds, - isDateHistogramBucketAggConfig, - createFormat, -} from '../../../legacy_imports'; -import { Vis, VisParams } from '..'; +import { SerializedFieldFormat } from '../../../../../../../plugins/expressions/public'; +import { fieldFormats, ISearchSource } from '../../../../../../../plugins/data/public'; +import { IAggConfig, setBounds, isDateHistogramBucketAggConfig } from '../../../legacy_imports'; +import { Vis, VisParams } from '../types'; interface SchemaConfigParams { precision?: number; @@ -102,7 +96,7 @@ export const getSchemas = (vis: Vis, timeRange?: any): Schemas => { 'max_bucket', ].includes(agg.type.name); - const format = createFormat( + const format = fieldFormats.serialize( hasSubAgg ? agg.params.customMetric || agg.aggConfigs.getRequestAggById(agg.params.metricAgg) : agg diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts index 9fb87cadb2983..b3dd22f62f81f 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts @@ -23,7 +23,7 @@ jest.mock('ui/vis/vis_factory'); jest.mock('ui/registry/vis_types'); jest.mock('./types/vis_type_alias_registry'); -import { PluginInitializerContext } from 'src/core/public'; +import { PluginInitializerContext } from '../../../../../../core/public'; import { VisualizationsSetup, VisualizationsStart } from './'; import { VisualizationsPlugin } from './plugin'; import { coreMock } from '../../../../../../core/public/mocks'; @@ -31,6 +31,7 @@ import { embeddablePluginMock } from '../../../../../../plugins/embeddable/publi import { expressionsPluginMock } from '../../../../../../plugins/expressions/public/mocks'; import { dataPluginMock } from '../../../../../../plugins/data/public/mocks'; import { usageCollectionPluginMock } from '../../../../../../plugins/usage_collection/public/mocks'; +import { uiActionsPluginMock } from '../../../../../../plugins/ui_actions/public/mocks'; const createSetupContract = (): VisualizationsSetup => ({ types: { @@ -47,7 +48,7 @@ const createStartContract = (): VisualizationsStart => ({ all: jest.fn(), getAliases: jest.fn(), }, - getSavedVisualizationsLoader: jest.fn(), + savedVisualizationsLoader: {} as any, showNewVisModal: jest.fn(), Vis: jest.fn(), }); @@ -64,6 +65,8 @@ const createInstance = async () => { const doStart = () => plugin.start(coreMock.createStart(), { data: dataPluginMock.createStartContract(), + expressions: expressionsPluginMock.createStartContract(), + uiActions: uiActionsPluginMock.createStartContract(), }); return { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts index 20bed59faad88..e1d87d414d398 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts @@ -17,8 +17,13 @@ * under the License. */ -import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public'; -import { TypesService, TypesSetup, TypesStart } from './types'; +import { + PluginInitializerContext, + CoreSetup, + CoreStart, + Plugin, +} from '../../../../../../core/public'; +import { TypesService, TypesSetup, TypesStart } from './vis_types'; import { setUISettings, setTypes, @@ -29,10 +34,13 @@ import { setSavedObjects, setUsageCollector, setFilterManager, + setExpressions, + setUiActions, + setSavedVisualizationsLoader, + setTimeFilter, } from './services'; -import { VisualizeEmbeddableFactory } from '../../embeddable/visualize_embeddable_factory'; -import { VISUALIZE_EMBEDDABLE_TYPE } from '../../embeddable'; -import { ExpressionsSetup } from '../../../../../../plugins/expressions/public'; +import { VISUALIZE_EMBEDDABLE_TYPE, VisualizeEmbeddableFactory } from './embeddable'; +import { ExpressionsSetup, ExpressionsStart } from '../../../../../../plugins/expressions/public'; import { IEmbeddableSetup } from '../../../../../../plugins/embeddable/public'; import { visualization as visualizationFunction } from './expressions/visualization_function'; import { visualization as visualizationRenderer } from './expressions/visualization_renderer'; @@ -41,13 +49,11 @@ import { DataPublicPluginStart, } from '../../../../../../plugins/data/public'; import { UsageCollectionSetup } from '../../../../../../plugins/usage_collection/public'; -import { - createSavedVisLoader, - SavedObjectKibanaServicesWithVisualizations, -} from '../../saved_visualizations'; -import { SavedVisualizations } from '../../../../kibana/public/visualize/np_ready/types'; +import { createSavedVisLoader, SavedVisualizationsLoader } from './saved_visualizations'; import { VisImpl, VisImplConstructor } from './vis_impl'; import { showNewVisModal } from './wizard'; +import { UiActionsStart } from '../../../../../../plugins/ui_actions/public'; + /** * Interface for this plugin's returned setup/start contracts. * @@ -59,9 +65,9 @@ export interface VisualizationsSetup { export interface VisualizationsStart { types: TypesStart; - getSavedVisualizationsLoader: () => SavedVisualizations; - showNewVisModal: typeof showNewVisModal; + savedVisualizationsLoader: SavedVisualizationsLoader; Vis: VisImplConstructor; + showNewVisModal: typeof showNewVisModal; } export interface VisualizationsSetupDeps { @@ -73,6 +79,8 @@ export interface VisualizationsSetupDeps { export interface VisualizationsStartDeps { data: DataPublicPluginStart; + expressions: ExpressionsStart; + uiActions: UiActionsStart; } /** @@ -92,8 +100,6 @@ export class VisualizationsPlugin VisualizationsStartDeps > { private readonly types: TypesService = new TypesService(); - private savedVisualizations?: SavedVisualizations; - private savedVisualizationDependencies?: SavedObjectKibanaServicesWithVisualizations; constructor(initializerContext: PluginInitializerContext) {} @@ -107,10 +113,7 @@ export class VisualizationsPlugin expressions.registerFunction(visualizationFunction); expressions.registerRenderer(visualizationRenderer); - const embeddableFactory = new VisualizeEmbeddableFactory( - data.query.timefilter.timefilter, - this.getSavedVisualizationsLoader - ); + const embeddableFactory = new VisualizeEmbeddableFactory(); embeddable.registerEmbeddableFactory(VISUALIZE_EMBEDDABLE_TYPE, embeddableFactory); return { @@ -118,7 +121,10 @@ export class VisualizationsPlugin }; } - public start(core: CoreStart, { data }: VisualizationsStartDeps): VisualizationsStart { + public start( + core: CoreStart, + { data, expressions, uiActions }: VisualizationsStartDeps + ): VisualizationsStart { const types = this.types.start(); setI18n(core.i18n); setTypes(types); @@ -127,31 +133,27 @@ export class VisualizationsPlugin setSavedObjects(core.savedObjects); setIndexPatterns(data.indexPatterns); setFilterManager(data.query.filterManager); - - this.savedVisualizationDependencies = { + setExpressions(expressions); + setUiActions(uiActions); + setTimeFilter(data.query.timefilter.timefilter); + const savedVisualizationsLoader = createSavedVisLoader({ savedObjectsClient: core.savedObjects.client, indexPatterns: data.indexPatterns, chrome: core.chrome, overlays: core.overlays, visualizationTypes: types, - }; + }); + setSavedVisualizationsLoader(savedVisualizationsLoader); return { types, - getSavedVisualizationsLoader: () => this.getSavedVisualizationsLoader(), showNewVisModal, Vis: VisImpl, + savedVisualizationsLoader, }; } public stop() { this.types.stop(); } - - private getSavedVisualizationsLoader = () => { - if (!this.savedVisualizations) { - this.savedVisualizations = createSavedVisLoader(this.savedVisualizationDependencies!); - } - return this.savedVisualizations; - }; } diff --git a/src/legacy/core_plugins/visualizations/public/saved_visualizations/_saved_vis.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/_saved_vis.ts similarity index 90% rename from src/legacy/core_plugins/visualizations/public/saved_visualizations/_saved_vis.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/_saved_vis.ts index f4548da375216..f3539b3564c56 100644 --- a/src/legacy/core_plugins/visualizations/public/saved_visualizations/_saved_vis.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/_saved_vis.ts @@ -28,15 +28,13 @@ import { createSavedObjectClass, SavedObject, SavedObjectKibanaServices, -} from '../../../../../plugins/saved_objects/public'; -import { updateOldState } from '../index'; +} from '../../../../../../../plugins/saved_objects/public'; +import { updateOldState } from '../../../index'; import { extractReferences, injectReferences } from './saved_visualization_references'; -import { IIndexPattern } from '../../../../../plugins/data/public'; -import { VisSavedObject } from '../embeddable/visualize_embeddable'; - -import { createSavedSearchesLoader } from '../../../kibana/public/discover'; -import { VisualizeConstants } from '../../../kibana/public/visualize'; -import { VisImpl } from '../np_ready/public/vis_impl'; +import { IIndexPattern } from '../../../../../../../plugins/data/public'; +import { VisSavedObject } from '../types'; +import { VisImpl } from '../vis_impl'; +import { createSavedSearchesLoader } from '../../../legacy_imports'; async function _afterEsResp(savedVis: VisSavedObject, services: any) { await _getLinkedSavedSearch(savedVis, services); @@ -138,7 +136,7 @@ export function createSavedVisClass(services: SavedObjectKibanaServices) { }); this.showInRecentlyAccessed = true; this.getFullPath = () => { - return `/app/kibana#${VisualizeConstants.EDIT_PATH}/${this.id}`; + return `/app/kibana#/visualize/edit/${this.id}`; }; } } diff --git a/src/legacy/core_plugins/visualizations/public/saved_visualizations/find_list_items.test.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/find_list_items.test.ts similarity index 77% rename from src/legacy/core_plugins/visualizations/public/saved_visualizations/find_list_items.test.js rename to src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/find_list_items.test.ts index ed0f6dc429ef4..d1def09978dbb 100644 --- a/src/legacy/core_plugins/visualizations/public/saved_visualizations/find_list_items.test.js +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/find_list_items.test.ts @@ -18,19 +18,24 @@ */ import { findListItems } from './find_list_items'; +import { coreMock } from '../../../../../../../core/public/mocks'; +import { SavedObjectsClientContract } from '../../../../../../../core/public'; +import { VisTypeAlias } from '../vis_types'; describe('saved_visualizations', () => { function testProps() { + const savedObjects = coreMock.createStart().savedObjects.client as jest.Mocked< + SavedObjectsClientContract + >; + (savedObjects.find as jest.Mock).mockImplementation(() => ({ + total: 0, + savedObjects: [], + })); return { visTypes: [], search: '', size: 10, - savedObjectsClient: { - find: jest.fn(async () => ({ - total: 0, - savedObjects: [], - })), - }, + savedObjectsClient: savedObjects, mapSavedObjectApiHits: jest.fn(), }; } @@ -60,7 +65,7 @@ describe('saved_visualizations', () => { searchFields: ['baz', 'bing'], }, }, - }, + } as VisTypeAlias, ], }; const { find } = props.savedObjectsClient; @@ -86,7 +91,7 @@ describe('saved_visualizations', () => { searchFields: ['baz', 'bing', 'barfield'], }, }, - }, + } as VisTypeAlias, { appExtensions: { visualizations: { @@ -94,7 +99,7 @@ describe('saved_visualizations', () => { searchFields: ['baz', 'bing', 'foofield'], }, }, - }, + } as VisTypeAlias, ], }; const { find } = props.savedObjectsClient; @@ -128,24 +133,11 @@ describe('saved_visualizations', () => { it('uses type-specific toListItem function, if available', async () => { const props = { ...testProps(), - savedObjectsClient: { - find: jest.fn(async () => ({ - total: 2, - savedObjects: [ - { - id: 'lotr', - type: 'wizard', - attributes: { label: 'Gandalf' }, - }, - { - id: 'wat', - type: 'visualization', - attributes: { title: 'WATEVER' }, - }, - ], - })), - }, - mapSavedObjectApiHits(savedObject) { + mapSavedObjectApiHits(savedObject: { + id: string; + type: string; + attributes: { title: string }; + }) { return { id: savedObject.id, title: `DEFAULT ${savedObject.attributes.title}`, @@ -159,14 +151,31 @@ describe('saved_visualizations', () => { toListItem(savedObject) { return { id: savedObject.id, - title: `${savedObject.attributes.label} THE GRAY`, + title: `${(savedObject.attributes as { label: string }).label} THE GRAY`, }; }, }, }, - }, + } as VisTypeAlias, ], }; + + (props.savedObjectsClient.find as jest.Mock).mockImplementationOnce(async () => ({ + total: 2, + savedObjects: [ + { + id: 'lotr', + type: 'wizard', + attributes: { label: 'Gandalf' }, + }, + { + id: 'wat', + type: 'visualization', + attributes: { title: 'WATEVER' }, + }, + ], + })); + const items = await findListItems(props); expect(items).toEqual({ total: 2, diff --git a/src/legacy/core_plugins/visualizations/public/saved_visualizations/find_list_items.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/find_list_items.ts similarity index 64% rename from src/legacy/core_plugins/visualizations/public/saved_visualizations/find_list_items.js rename to src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/find_list_items.ts index a7fcee67adf72..02db90a762e89 100644 --- a/src/legacy/core_plugins/visualizations/public/saved_visualizations/find_list_items.js +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/find_list_items.ts @@ -18,6 +18,13 @@ */ import _ from 'lodash'; +import { + SavedObjectAttributes, + SavedObjectsClientContract, +} from '../../../../../../../core/public'; +import { SavedObjectLoader } from '../../../../../../../plugins/saved_objects/public'; +import { VisTypeAlias } from '../vis_types'; +import { VisualizationsAppExtension } from '../vis_types/vis_type_alias_registry'; /** * Search for visualizations and convert them into a list display-friendly format. @@ -28,34 +35,42 @@ export async function findListItems({ size, savedObjectsClient, mapSavedObjectApiHits, +}: { + search: string; + size: number; + visTypes: VisTypeAlias[]; + savedObjectsClient: SavedObjectsClientContract; + mapSavedObjectApiHits: SavedObjectLoader['mapSavedObjectApiHits']; }) { - const extensions = _.compact( - visTypes.map(v => v.appExtensions && v.appExtensions.visualizations) - ); + const extensions = visTypes + .map(v => v.appExtensions?.visualizations) + .filter(Boolean) as VisualizationsAppExtension[]; const extensionByType = extensions.reduce((acc, m) => { - return m.docTypes.reduce((_acc, type) => { + return m!.docTypes.reduce((_acc, type) => { acc[type] = m; return acc; }, acc); - }, {}); - const searchOption = (field, ...defaults) => + }, {} as { [visType: string]: VisualizationsAppExtension }); + const searchOption = (field: string, ...defaults: string[]) => _(extensions) .pluck(field) .concat(defaults) .compact() .flatten() .uniq() - .value(); + .value() as string[]; const searchOptions = { type: searchOption('docTypes', 'visualization'), searchFields: searchOption('searchFields', 'title^3', 'description'), search: search ? `${search}*` : undefined, perPage: size, page: 1, - defaultSearchOperator: 'AND', + defaultSearchOperator: 'AND' as 'AND', }; - const { total, savedObjects } = await savedObjectsClient.find(searchOptions); + const { total, savedObjects } = await savedObjectsClient.find( + searchOptions + ); return { total, diff --git a/src/legacy/core_plugins/visualizations/public/saved_visualizations/index.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/index.ts similarity index 100% rename from src/legacy/core_plugins/visualizations/public/saved_visualizations/index.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/index.ts diff --git a/src/legacy/core_plugins/visualizations/public/saved_visualizations/saved_visualization_references.test.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualization_references.test.ts similarity index 96% rename from src/legacy/core_plugins/visualizations/public/saved_visualizations/saved_visualization_references.test.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualization_references.test.ts index 6549b317d1634..98af6d99025c2 100644 --- a/src/legacy/core_plugins/visualizations/public/saved_visualizations/saved_visualization_references.test.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualization_references.test.ts @@ -18,7 +18,7 @@ */ import { extractReferences, injectReferences } from './saved_visualization_references'; -import { VisSavedObject } from '../embeddable/visualize_embeddable'; +import { VisSavedObject, VisState } from '../types'; describe('extractReferences', () => { test('extracts nothing if savedSearchId is empty', () => { @@ -128,7 +128,7 @@ Object { id: '1', title: 'test', savedSearchRefName: 'search_0', - visState: { + visState: ({ params: { controls: [ { @@ -140,7 +140,7 @@ Object { }, ], }, - }, + } as unknown) as VisState, } as VisSavedObject; const references = [ { @@ -192,7 +192,7 @@ Object { const context = { id: '1', title: 'test', - visState: { + visState: ({ params: { controls: [ { @@ -201,7 +201,7 @@ Object { }, ], }, - }, + } as unknown) as VisState, } as VisSavedObject; expect(() => injectReferences(context, [])).toThrowErrorMatchingInlineSnapshot( `"Could not find index pattern reference \\"control_0_index_pattern\\""` diff --git a/src/legacy/core_plugins/visualizations/public/saved_visualizations/saved_visualization_references.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualization_references.ts similarity index 95% rename from src/legacy/core_plugins/visualizations/public/saved_visualizations/saved_visualization_references.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualization_references.ts index 330f5e2dacd10..b995d340d44d9 100644 --- a/src/legacy/core_plugins/visualizations/public/saved_visualizations/saved_visualization_references.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualization_references.ts @@ -16,8 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import { SavedObjectAttributes, SavedObjectReference } from 'kibana/public'; -import { VisSavedObject } from '../embeddable/visualize_embeddable'; +import { SavedObjectAttributes, SavedObjectReference } from '../../../../../../../core/public'; +import { VisSavedObject } from '../types'; export function extractReferences({ attributes, diff --git a/src/legacy/core_plugins/visualizations/public/saved_visualizations/saved_visualizations.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualizations.ts similarity index 91% rename from src/legacy/core_plugins/visualizations/public/saved_visualizations/saved_visualizations.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualizations.ts index 7d0d6a10ff66f..fc0f77d54059c 100644 --- a/src/legacy/core_plugins/visualizations/public/saved_visualizations/saved_visualizations.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualizations.ts @@ -19,18 +19,15 @@ import { SavedObjectLoader, SavedObjectKibanaServices, -} from '../../../../../plugins/saved_objects/public'; - -// @ts-ignore +} from '../../../../../../../plugins/saved_objects/public'; import { findListItems } from './find_list_items'; import { createSavedVisClass } from './_saved_vis'; -import { createVisualizeEditUrl } from '../../../kibana/public/visualize'; -import { TypesStart } from '../np_ready/public/types'; +import { TypesStart } from '../vis_types'; export interface SavedObjectKibanaServicesWithVisualizations extends SavedObjectKibanaServices { visualizationTypes: TypesStart; } - +export type SavedVisualizationsLoader = ReturnType; export function createSavedVisLoader(services: SavedObjectKibanaServicesWithVisualizations) { const { savedObjectsClient, visualizationTypes } = services; @@ -59,7 +56,7 @@ export function createSavedVisLoader(services: SavedObjectKibanaServicesWithVisu source.icon = source.type.icon; source.image = source.type.image; source.typeTitle = source.type.title; - source.editUrl = `#${createVisualizeEditUrl(id)}`; + source.editUrl = `#/visualize/edit/${id}`; return source; }; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/services.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/services.ts index 433c5c7b6df0d..a977a4b452bf7 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/services.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/services.ts @@ -23,11 +23,18 @@ import { I18nStart, IUiSettingsClient, SavedObjectsStart, -} from 'src/core/public'; -import { TypesStart } from './types'; +} from '../../../../../../core/public'; +import { TypesStart } from './vis_types'; import { createGetterSetter } from '../../../../../../plugins/kibana_utils/public'; -import { FilterManager, IndexPatternsContract } from '../../../../../../plugins/data/public'; +import { + FilterManager, + IndexPatternsContract, + TimefilterContract, +} from '../../../../../../plugins/data/public'; import { UsageCollectionSetup } from '../../../../../../plugins/usage_collection/public'; +import { ExpressionsStart } from '../../../../../../plugins/expressions/public'; +import { UiActionsStart } from '../../../../../../plugins/ui_actions/public'; +import { SavedVisualizationsLoader } from './saved_visualizations'; export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); @@ -47,6 +54,8 @@ export const [getFilterManager, setFilterManager] = createGetterSetter('TimeFilter'); + export const [getIndexPatterns, setIndexPatterns] = createGetterSetter( 'IndexPatterns' ); @@ -54,3 +63,11 @@ export const [getIndexPatterns, setIndexPatterns] = createGetterSetter( 'UsageCollection' ); + +export const [getExpressions, setExpressions] = createGetterSetter('Expressions'); + +export const [getUiActions, setUiActions] = createGetterSetter('UiActions'); + +export const [getSavedVisualizationsLoader, setSavedVisualizationsLoader] = createGetterSetter< + SavedVisualizationsLoader +>('SavedVisualisationsLoader'); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/types.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/types.ts new file mode 100644 index 0000000000000..d2ca4ffb92eb2 --- /dev/null +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/types.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 { SavedObject } from '../../../../../../plugins/saved_objects/public'; +import { Vis, VisState, VisParams, VisualizationController } from './vis'; +import { ISearchSource } from '../../../../../../plugins/data/public/'; +import { SavedSearch } from '../../../../kibana/public/discover/np_ready/types'; + +export { Vis, VisState, VisParams, VisualizationController }; + +export interface VisSavedObject extends SavedObject { + vis: Vis; + description?: string; + searchSource: ISearchSource; + title: string; + uiStateJSON?: string; + destroy: () => void; + savedSearchRefName?: string; + savedSearchId?: string; + savedSearch?: SavedSearch; + visState: VisState; +} diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts index 19375e25a9fb7..990f27dca7556 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts @@ -17,7 +17,7 @@ * under the License. */ -import { VisType } from './types'; +import { VisType } from './vis_types'; import { IAggConfigs } from '../../legacy_imports'; import { Status } from './legacy/update_status'; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts index f9b7db5c02d93..62b68082e21f8 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts @@ -18,7 +18,7 @@ */ import { Vis, VisState, VisParams } from './vis'; -import { VisType } from './types'; +import { VisType } from './vis_types'; import { IIndexPattern } from '../../../../../../plugins/data/common'; type InitVisStateType = diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/types/base_vis_type.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/base_vis_type.js similarity index 95% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/types/base_vis_type.js rename to src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/base_vis_type.js index 351acc48e2676..50ff74cfe9dd3 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/types/base_vis_type.js +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/base_vis_type.js @@ -19,8 +19,6 @@ import _ from 'lodash'; -import { DefaultEditorController } from '../../../../../vis_default_editor/public'; - export class BaseVisType { constructor(opts = {}) { if (!opts.name) { @@ -47,7 +45,7 @@ export class BaseVisType { }, requestHandler: 'courier', // select one from registry or pass a function responseHandler: 'none', - editor: DefaultEditorController, + editor: null, // no default is provided editorConfig: { collections: {}, // collections used for configuration (list of positions, ...) }, diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/types/index.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/index.ts similarity index 100% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/types/index.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/index.ts diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/types/react_vis_type.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/react_vis_type.js similarity index 100% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/types/react_vis_type.js rename to src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/react_vis_type.js diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/types/types_service.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/types_service.ts similarity index 100% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/types/types_service.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/types_service.ts diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/types/vis_type_alias_registry.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/vis_type_alias_registry.ts similarity index 97% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/types/vis_type_alias_registry.ts rename to src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/vis_type_alias_registry.ts index 97f4798c296d4..12b02ee9e6b32 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/types/vis_type_alias_registry.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types/vis_type_alias_registry.ts @@ -27,7 +27,7 @@ interface VisualizationListItem { typeTitle: string; } -interface VisualizationsAppExtension { +export interface VisualizationsAppExtension { docTypes: string[]; searchFields?: string[]; toListItem: (savedObject: { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.test.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.test.tsx index 58f7bc49d1cdb..2712019e42609 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.test.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.test.tsx @@ -19,9 +19,9 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { TypesStart, VisType } from '../types'; +import { TypesStart, VisType } from '../vis_types'; import { NewVisModal } from './new_vis_modal'; -import { SavedObjectsStart } from 'kibana/public'; +import { SavedObjectsStart } from '../../../../../../../core/public'; describe('NewVisModal', () => { const { location } = window; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.tsx index b39e8e8926707..7c10001eddb50 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/new_vis_modal.tsx @@ -23,10 +23,10 @@ import { EuiModal, EuiOverlayMask } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { METRIC_TYPE, UiStatsMetricType } from '@kbn/analytics'; -import { IUiSettingsClient, SavedObjectsStart } from 'kibana/public'; +import { IUiSettingsClient, SavedObjectsStart } from '../../../../../../../core/public'; import { SearchSelection } from './search_selection'; import { TypeSelection } from './type_selection'; -import { TypesStart, VisType, VisTypeAlias } from '../types'; +import { TypesStart, VisType, VisTypeAlias } from '../vis_types'; import { UsageCollectionSetup } from '../../../../../../../plugins/usage_collection/public'; interface TypeSelectionProps { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/search_selection/search_selection.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/search_selection/search_selection.tsx index 9b3b8a6425e52..f8eb191dd5f92 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/search_selection/search_selection.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/search_selection/search_selection.tsx @@ -21,10 +21,10 @@ import { EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui' import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; -import { IUiSettingsClient, SavedObjectsStart } from 'kibana/public'; +import { IUiSettingsClient, SavedObjectsStart } from '../../../../../../../../core/public'; import { SavedObjectFinderUi } from '../../../../../../../../plugins/saved_objects/public'; -import { VisType } from '../../types'; +import { VisType } from '../../vis_types'; interface SearchSelectionProps { onSearchSelected: (searchId: string, searchType: string) => void; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/new_vis_help.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/new_vis_help.tsx index 5068f43952c4e..e84314853ba4c 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/new_vis_help.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/new_vis_help.tsx @@ -21,7 +21,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import React, { Fragment } from 'react'; import { EuiText, EuiButton } from '@elastic/eui'; import { VisTypeAliasListEntry } from './type_selection'; -import { VisTypeAlias } from '../../types'; +import { VisTypeAlias } from '../../vis_types'; interface Props { promotedTypes: VisTypeAliasListEntry[]; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/type_selection.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/type_selection.tsx index 574f5b3cccc99..81dcecfee2613 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/type_selection.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/wizard/type_selection/type_selection.tsx @@ -40,7 +40,7 @@ import { VisTypeAlias } from '../../../../../../visualizations/public'; import { NewVisHelp } from './new_vis_help'; import { VisHelpText } from './vis_help_text'; import { VisTypeIcon } from './vis_type_icon'; -import { VisType, TypesStart } from '../../types'; +import { VisType, TypesStart } from '../../vis_types'; export interface VisTypeListEntry extends VisType { highlighted: boolean; diff --git a/src/plugins/saved_objects/public/save_modal/saved_object_save_modal.tsx b/src/plugins/saved_objects/public/save_modal/saved_object_save_modal.tsx index da70d9fe89525..275a9da96a2c4 100644 --- a/src/plugins/saved_objects/public/save_modal/saved_object_save_modal.tsx +++ b/src/plugins/saved_objects/public/save_modal/saved_object_save_modal.tsx @@ -39,7 +39,11 @@ import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; import { EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { VISUALIZE_EMBEDDABLE_TYPE } from '../../../../legacy/core_plugins/visualizations/public/embeddable/constants'; + +// TODO: can't import from '../../../../legacy/core_plugins/visualizations/public/' directly, +// because yarn build:types fails after trying to emit type declarations for whole visualizations plugin +// Bunch of errors like this: 'Return type of exported function has or is using private name 'SavedVis'' +import { VISUALIZE_EMBEDDABLE_TYPE } from '../../../../legacy/core_plugins/visualizations/public/np_ready/public/embeddable/constants'; export interface OnSaveProps { newTitle: string; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/expression_types/embeddable_types.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/expression_types/embeddable_types.ts index cc92d864282e7..d9e841092be56 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/expression_types/embeddable_types.ts +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/expression_types/embeddable_types.ts @@ -6,7 +6,7 @@ // @ts-ignore import { MAP_SAVED_OBJECT_TYPE } from '../../../maps/common/constants'; -import { VISUALIZE_EMBEDDABLE_TYPE } from '../../../../../../src/legacy/core_plugins/visualizations/public/embeddable/constants'; +import { VISUALIZE_EMBEDDABLE_TYPE } from '../../../../../../src/legacy/core_plugins/visualizations/public'; import { SEARCH_EMBEDDABLE_TYPE } from '../../../../../../src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/constants'; export const EmbeddableTypes: { map: string; search: string; visualization: string } = { diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/saved_visualization.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/saved_visualization.ts index 6ac0d84bc9a73..0315a1f480911 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/saved_visualization.ts +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/saved_visualization.ts @@ -5,7 +5,7 @@ */ import { ExpressionFunctionDefinition } from 'src/plugins/expressions'; -import { VisualizeInput } from 'src/legacy/core_plugins/visualizations/public/embeddable'; +import { VisualizeInput } from 'src/legacy/core_plugins/visualizations/public'; import { EmbeddableTypes, EmbeddableExpressionType, diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression.test.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression.test.ts index 93d747537c34c..8694c0e2c7f9f 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression.test.ts +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression.test.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +jest.mock('ui/new_platform'); import { embeddableInputToExpression } from './embeddable_input_to_expression'; import { SavedMapInput } from '../../functions/common/saved_map'; import { EmbeddableTypes } from '../../expression_types'; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index dc97a96d4fcba..dc8d6343007b8 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2872,7 +2872,6 @@ "visualizations.newVisWizard.title": "新規ビジュアライゼーション", "visualizations.newVisWizard.visTypeAliasDescription": "Visualize外でKibanaアプリケーションを開きます。", "visualizations.newVisWizard.visTypeAliasTitle": "Kibanaアプリケーション", - "visualizations.queryGeohashBounds.unableToGetBoundErrorTitle": "バウンドを取得できませんでした", "visDefaultEditor.aggSelect.aggregationLabel": "集約", "visDefaultEditor.aggSelect.helpLinkLabel": "{aggTitle} のヘルプ", "visDefaultEditor.aggSelect.noCompatibleAggsDescription": "インデックスパターン{indexPatternTitle}には集約可能なフィールドが含まれていません。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 2532cdb0c4d07..f6ef0140e385e 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2873,7 +2873,6 @@ "visualizations.newVisWizard.title": "新建可视化", "visualizations.newVisWizard.visTypeAliasDescription": "打开 Visualize 外部的 Kibana 应用程序。", "visualizations.newVisWizard.visTypeAliasTitle": "Kibana 应用程序", - "visualizations.queryGeohashBounds.unableToGetBoundErrorTitle": "无法获取边界", "visDefaultEditor.aggSelect.aggregationLabel": "聚合", "visDefaultEditor.aggSelect.helpLinkLabel": "{aggTitle} 帮助", "visDefaultEditor.aggSelect.noCompatibleAggsDescription": "索引模式“{indexPatternTitle}”不包含任何聚合。", From d50031e7215ea66eb1b7e2ee20b2897ae3b9a5b7 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 25 Feb 2020 18:02:40 +0000 Subject: [PATCH 067/123] [ML] Global calendars (#57890) * [ML] Global calendars * updating snapshots * changes based on review * larger spacer * updating jest snapshot --- .../plugins/ml/common/constants/calendars.ts | 7 ++ .../calendars/calendars_selection.tsx | 5 +- .../__snapshots__/new_calendar.test.js.snap | 2 + .../__snapshots__/calendar_form.test.js.snap | 56 ++---------- .../edit/calendar_form/calendar_form.js | 85 ++++++++++++------- .../settings/calendars/edit/new_calendar.js | 42 ++++++--- .../settings/calendars/edit/utils.js | 17 ++-- .../table/__snapshots__/table.test.js.snap | 1 + .../settings/calendars/list/table/table.js | 14 +++ .../server/models/calendar/event_manager.ts | 4 +- .../ml/server/models/job_service/groups.js | 18 ++-- 11 files changed, 148 insertions(+), 103 deletions(-) create mode 100644 x-pack/legacy/plugins/ml/common/constants/calendars.ts diff --git a/x-pack/legacy/plugins/ml/common/constants/calendars.ts b/x-pack/legacy/plugins/ml/common/constants/calendars.ts new file mode 100644 index 0000000000000..1a56257ca1304 --- /dev/null +++ b/x-pack/legacy/plugins/ml/common/constants/calendars.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export const GLOBAL_CALENDAR = '_all'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/calendars_selection.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/calendars_selection.tsx index 919972186761a..1e7327552623e 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/calendars_selection.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/calendars_selection.tsx @@ -23,6 +23,7 @@ import { JobCreatorContext } from '../../../../../job_creator_context'; import { Description } from './description'; import { ml } from '../../../../../../../../../services/ml_api_service'; import { Calendar } from '../../../../../../../../../../../common/types/calendars'; +import { GLOBAL_CALENDAR } from '../../../../../../../../../../../common/constants/calendars'; export const CalendarsSelection: FC = () => { const { jobCreator, jobCreatorUpdate } = useContext(JobCreatorContext); @@ -35,7 +36,9 @@ export const CalendarsSelection: FC = () => { async function loadCalendars() { setIsLoading(true); - const calendars = await ml.calendars(); + const calendars = (await ml.calendars()).filter( + c => c.job_ids.includes(GLOBAL_CALENDAR) === false + ); setOptions(calendars.map(c => ({ label: c.calendar_id, value: c }))); setSelectedOptions(selectedCalendars.map(c => ({ label: c.calendar_id, value: c }))); setIsLoading(false); diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/__snapshots__/new_calendar.test.js.snap b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/__snapshots__/new_calendar.test.js.snap index 2f5eb596a157b..21f505cff9aec 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/__snapshots__/new_calendar.test.js.snap +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/__snapshots__/new_calendar.test.js.snap @@ -22,6 +22,7 @@ exports[`NewCalendar Renders new calendar form 1`] = ` eventsList={Array []} groupIds={Array []} isEdit={false} + isGlobalCalendar={false} isNewCalendarIdValid={true} jobIds={Array []} onCalendarIdChange={[Function]} @@ -30,6 +31,7 @@ exports[`NewCalendar Renders new calendar form 1`] = ` onDescriptionChange={[Function]} onEdit={[Function]} onEventDelete={[Function]} + onGlobalCalendarChange={[Function]} onGroupSelection={[Function]} onJobSelection={[Function]} saving={false} diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/__snapshots__/calendar_form.test.js.snap b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/__snapshots__/calendar_form.test.js.snap index 0e7db62e44b51..acce01f1994db 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/__snapshots__/calendar_form.test.js.snap +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/__snapshots__/calendar_form.test.js.snap @@ -84,59 +84,19 @@ exports[`CalendarForm Renders calendar form 1`] = ` value="" /> - - } - labelType="label" - > - - - + } - labelType="label" - > - - + name="switch" + /> diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/calendar_form.js b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/calendar_form.js index fffcdf4c516f8..62daced72ceb2 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/calendar_form.js +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/calendar_form.js @@ -18,6 +18,7 @@ import { EuiSpacer, EuiText, EuiTitle, + EuiSwitch, } from '@elastic/eui'; import { EventsTable } from '../events_table'; @@ -68,6 +69,8 @@ export const CalendarForm = ({ selectedGroupOptions, selectedJobOptions, showNewEventModal, + isGlobalCalendar, + onGlobalCalendarChange, }) => { const msg = i18n.translate('xpack.ml.calendarsEdit.calendarForm.allowedCharactersDescription', { defaultMessage: @@ -81,7 +84,9 @@ export const CalendarForm = ({ return ( - {!isEdit && ( + {isEdit === true ? ( + + ) : (

@@ -128,39 +133,59 @@ export const CalendarForm = ({ )} - {isEdit && } - - } - > - - - + + } - > - - + checked={isGlobalCalendar} + onChange={onGlobalCalendarChange} + /> + + {isGlobalCalendar === false && ( + <> + + + + } + > + + + + + } + > + + + + )} @@ -240,4 +265,6 @@ CalendarForm.propTypes = { selectedGroupOptions: PropTypes.array.isRequired, selectedJobOptions: PropTypes.array.isRequired, showNewEventModal: PropTypes.func.isRequired, + isGlobalCalendar: PropTypes.bool.isRequired, + onGlobalCalendarChange: PropTypes.func.isRequired, }; diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.js b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.js index 935e67ec05eff..815d1565d5bc4 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.js +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.js @@ -19,6 +19,7 @@ import { NewEventModal } from './new_event_modal'; import { ImportModal } from './import_modal'; import { ml } from '../../../services/ml_api_service'; import { withKibana } from '../../../../../../../../../src/plugins/kibana_react/public'; +import { GLOBAL_CALENDAR } from '../../../../../common/constants/calendars'; class NewCalendarUI extends Component { static propTypes = { @@ -46,6 +47,7 @@ class NewCalendarUI extends Component { events: [], saving: false, selectedCalendar: undefined, + isGlobalCalendar: false, }; } @@ -65,6 +67,7 @@ class NewCalendarUI extends Component { let eventsList = []; let selectedCalendar; let formCalendarId = ''; + let isGlobalCalendar = false; // Editing existing calendar. if (this.props.calendarId !== undefined) { @@ -74,13 +77,17 @@ class NewCalendarUI extends Component { formCalendarId = selectedCalendar.calendar_id; eventsList = selectedCalendar.events; - selectedCalendar.job_ids.forEach(id => { - if (jobIds.find(jobId => jobId === id)) { - selectedJobOptions.push({ label: id }); - } else if (groupIds.find(groupId => groupId === id)) { - selectedGroupOptions.push({ label: id }); - } - }); + if (selectedCalendar.job_ids.includes(GLOBAL_CALENDAR)) { + isGlobalCalendar = true; + } else { + selectedCalendar.job_ids.forEach(id => { + if (jobIds.find(jobId => jobId === id)) { + selectedJobOptions.push({ label: id }); + } else if (groupIds.find(groupId => groupId === id)) { + selectedGroupOptions.push({ label: id }); + } + }); + } } } @@ -96,6 +103,7 @@ class NewCalendarUI extends Component { selectedJobOptions, selectedGroupOptions, selectedCalendar, + isGlobalCalendar, }); } catch (error) { console.log(error); @@ -181,10 +189,15 @@ class NewCalendarUI extends Component { events, selectedGroupOptions, selectedJobOptions, + isGlobalCalendar, } = this.state; - const jobIds = selectedJobOptions.map(option => option.label); - const groupIds = selectedGroupOptions.map(option => option.label); + const allIds = isGlobalCalendar + ? [GLOBAL_CALENDAR] + : [ + ...selectedJobOptions.map(option => option.label), + ...selectedGroupOptions.map(option => option.label), + ]; // Reduce events to fields expected by api const eventsToSave = events.map(event => ({ @@ -198,7 +211,7 @@ class NewCalendarUI extends Component { calendarId: formCalendarId, description, events: eventsToSave, - job_ids: [...jobIds, ...groupIds], + job_ids: allIds, }; return calendar; @@ -214,6 +227,12 @@ class NewCalendarUI extends Component { })); }; + onGlobalCalendarChange = ({ currentTarget }) => { + this.setState({ + isGlobalCalendar: currentTarget.checked, + }); + }; + onJobSelection = selectedJobOptions => { this.setState({ selectedJobOptions, @@ -295,6 +314,7 @@ class NewCalendarUI extends Component { selectedCalendar, selectedJobOptions, selectedGroupOptions, + isGlobalCalendar, } = this.state; let modal = ''; @@ -351,6 +371,8 @@ class NewCalendarUI extends Component { selectedJobOptions={selectedJobOptions} onCreateGroupOption={this.onCreateGroupOption} showNewEventModal={this.showNewEventModal} + isGlobalCalendar={isGlobalCalendar} + onGlobalCalendarChange={this.onGlobalCalendarChange} /> {modal} diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/utils.js b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/utils.js index e4ab6677accf5..efc54c181fdc1 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/utils.js +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/utils.js @@ -73,14 +73,17 @@ function getCalendars() { export function getCalendarSettingsData() { return new Promise(async (resolve, reject) => { try { - const data = await Promise.all([getJobIds(), getGroupIds(), getCalendars()]); + const [jobIds, groupIds, calendars] = await Promise.all([ + getJobIds(), + getGroupIds(), + getCalendars(), + ]); - const formattedData = { - jobIds: data[0], - groupIds: data[1], - calendars: data[2], - }; - resolve(formattedData); + resolve({ + jobIds, + groupIds, + calendars, + }); } catch (error) { console.log(error); reject(error); diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/__snapshots__/table.test.js.snap b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/__snapshots__/table.test.js.snap index ff74c592b2b0f..14b65a04ce599 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/__snapshots__/table.test.js.snap +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/__snapshots__/table.test.js.snap @@ -16,6 +16,7 @@ exports[`CalendarsListTable renders the table with all calendars 1`] = ` Object { "field": "job_ids_string", "name": "Jobs", + "render": [Function], "sortable": true, "truncateText": true, }, diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/table.js b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/table.js index bd1dafcd6c0aa..be41eabd5ae2d 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/table.js +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/table.js @@ -12,6 +12,8 @@ import { EuiButton, EuiLink, EuiInMemoryTable } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { GLOBAL_CALENDAR } from '../../../../../../common/constants/calendars'; + export const CalendarsListTable = ({ calendarsList, onDeleteClick, @@ -52,6 +54,18 @@ export const CalendarsListTable = ({ }), sortable: true, truncateText: true, + render: jobList => { + return jobList === GLOBAL_CALENDAR ? ( + + + + ) : ( + jobList + ); + }, }, { field: 'events_length', diff --git a/x-pack/legacy/plugins/ml/server/models/calendar/event_manager.ts b/x-pack/legacy/plugins/ml/server/models/calendar/event_manager.ts index 19f2eda466179..488839f68b3fe 100644 --- a/x-pack/legacy/plugins/ml/server/models/calendar/event_manager.ts +++ b/x-pack/legacy/plugins/ml/server/models/calendar/event_manager.ts @@ -6,6 +6,8 @@ import Boom from 'boom'; +import { GLOBAL_CALENDAR } from '../../../common/constants/calendars'; + export interface CalendarEvent { calendar_id?: string; event_id?: string; @@ -32,7 +34,7 @@ export class EventManager { // jobId is optional async getAllEvents(jobId?: string) { - const calendarId = '_all'; + const calendarId = GLOBAL_CALENDAR; try { const resp = await this._client('ml.events', { calendarId, diff --git a/x-pack/legacy/plugins/ml/server/models/job_service/groups.js b/x-pack/legacy/plugins/ml/server/models/job_service/groups.js index 91f82f04a9a0c..6fbc071ef9854 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_service/groups.js +++ b/x-pack/legacy/plugins/ml/server/models/job_service/groups.js @@ -5,6 +5,7 @@ */ import { CalendarManager } from '../calendar'; +import { GLOBAL_CALENDAR } from '../../../common/constants/calendars'; export function groupsProvider(callWithRequest) { const calMngr = new CalendarManager(callWithRequest); @@ -12,11 +13,13 @@ export function groupsProvider(callWithRequest) { async function getAllGroups() { const groups = {}; const jobIds = {}; - const [JOBS, CALENDARS] = [0, 1]; - const results = await Promise.all([callWithRequest('ml.jobs'), calMngr.getAllCalendars()]); + const [{ jobs }, calendars] = await Promise.all([ + callWithRequest('ml.jobs'), + calMngr.getAllCalendars(), + ]); - if (results[JOBS] && results[JOBS].jobs) { - results[JOBS].jobs.forEach(job => { + if (jobs) { + jobs.forEach(job => { jobIds[job.job_id] = null; if (job.groups !== undefined) { job.groups.forEach(g => { @@ -33,10 +36,11 @@ export function groupsProvider(callWithRequest) { } }); } - if (results[CALENDARS]) { - results[CALENDARS].forEach(cal => { + if (calendars) { + calendars.forEach(cal => { cal.job_ids.forEach(jId => { - if (jobIds[jId] === undefined) { + // don't include _all in the calendar groups list + if (jId !== GLOBAL_CALENDAR && jobIds[jId] === undefined) { if (groups[jId] === undefined) { groups[jId] = { id: jId, From 30fb4eb6945a463aeec1211d04854735c3c75281 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 25 Feb 2020 11:50:54 -0700 Subject: [PATCH 068/123] [Maps] remove duplicated pagintation text in locked tooltips (#58383) --- .../__snapshots__/tooltip_header.test.js.snap | 38 ------------------- .../map/features_tooltip/tooltip_header.js | 2 +- 2 files changed, 1 insertion(+), 39 deletions(-) diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/__snapshots__/tooltip_header.test.js.snap b/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/__snapshots__/tooltip_header.test.js.snap index 486a830d21b65..b5fe334f8415e 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/__snapshots__/tooltip_header.test.js.snap +++ b/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/__snapshots__/tooltip_header.test.js.snap @@ -17,25 +17,6 @@ exports[`TooltipHeader multiple features, multiple layers: locked should show pa pageCount={3} /> - - - - - @@ -139,25 +120,6 @@ exports[`TooltipHeader multiple features, single layer: locked should show pagin pageCount={2} /> - - - - - 1) { + if (!isLocked && filteredFeatures.length > 1) { headerItems.push( From d9e3d744ba83554139c0c4383b2167a577577b29 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 25 Feb 2020 14:21:25 -0500 Subject: [PATCH 069/123] [Maps] Add EPSG-code to docs (#58378) --- docs/setup/settings.asciidoc | 2 +- .../file_upload/public/components/json_index_file_picker.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index c1f06aff722b5..2d4d00b730109 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -231,7 +231,7 @@ This setting does not impact <> and <> visualizations. Supported on {ece}. Each layer object points to an external vector file that contains a geojson FeatureCollection. The file must use the -https://en.wikipedia.org/wiki/World_Geodetic_System[WGS84 coordinate reference system] +https://en.wikipedia.org/wiki/World_Geodetic_System[WGS84 coordinate reference system (ESPG:4326)] and only include polygons. If the file is hosted on a separate domain from Kibana, the server needs to be CORS-enabled so Kibana can download the file. The following example shows a valid regionmap configuration. diff --git a/x-pack/legacy/plugins/file_upload/public/components/json_index_file_picker.js b/x-pack/legacy/plugins/file_upload/public/components/json_index_file_picker.js index 0ee4f76ebf9d0..67086883a9a32 100644 --- a/x-pack/legacy/plugins/file_upload/public/components/json_index_file_picker.js +++ b/x-pack/legacy/plugins/file_upload/public/components/json_index_file_picker.js @@ -268,6 +268,10 @@ export class JsonIndexFilePicker extends Component { maxFileSize: bytesToSize(MAX_FILE_SIZE), }} /> +
+ {i18n.translate('xpack.fileUpload.jsonIndexFilePicker.coordinateSystemAccepted', { + defaultMessage: 'Coordinates must be in EPSG:4326 coordinate reference system.', + })}{' '} ) } From 7b4c809fc7b29ffead03daac0363d3701d2f016a Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 25 Feb 2020 13:51:02 -0700 Subject: [PATCH 070/123] Abort cancelled search requests to Elasticsearch (#56788) * Update abort controller library * Bootstrap * Abort when the request is aborted * Add utility and update value suggestions route * Remove bad merge * Revert switching abort controller libraries * Revert package.json in lib * Move to previous abort controller * Fix test to use fake timers to run debounced handlers * Fix loading bar not going away when cancelling * Add test for loading count * Fix test * Fix failing test Co-authored-by: Elastic Machine --- .../search/sync_search_strategy.test.ts | 52 ++++++++++++++++--- .../public/search/sync_search_strategy.ts | 21 ++++---- .../autocomplete/value_suggestions_route.ts | 4 +- .../lib/get_request_aborted_signal.test.ts | 45 ++++++++++++++++ .../server/lib/get_request_aborted_signal.ts | 33 ++++++++++++ src/plugins/data/server/lib/index.ts | 20 +++++++ src/plugins/data/server/search/routes.ts | 5 +- 7 files changed, 161 insertions(+), 19 deletions(-) create mode 100644 src/plugins/data/server/lib/get_request_aborted_signal.test.ts create mode 100644 src/plugins/data/server/lib/get_request_aborted_signal.ts create mode 100644 src/plugins/data/server/lib/index.ts diff --git a/src/plugins/data/public/search/sync_search_strategy.test.ts b/src/plugins/data/public/search/sync_search_strategy.test.ts index 9378e5833f8d7..31a1adfa01c75 100644 --- a/src/plugins/data/public/search/sync_search_strategy.test.ts +++ b/src/plugins/data/public/search/sync_search_strategy.test.ts @@ -35,12 +35,9 @@ describe('Sync search strategy', () => { core: mockCoreStart, getSearchStrategy: jest.fn(), }); - syncSearch.search( - { - serverStrategy: SYNC_SEARCH_STRATEGY, - }, - {} - ); + const request = { serverStrategy: SYNC_SEARCH_STRATEGY }; + syncSearch.search(request, {}); + expect(mockCoreStart.http.fetch.mock.calls[0][0]).toEqual({ path: `/internal/search/${SYNC_SEARCH_STRATEGY}`, body: JSON.stringify({ @@ -50,4 +47,47 @@ describe('Sync search strategy', () => { signal: undefined, }); }); + + it('increments and decrements loading count on success', async () => { + const expectedLoadingCountValues = [0, 1, 0]; + const receivedLoadingCountValues: number[] = []; + + mockCoreStart.http.fetch.mockResolvedValueOnce('response'); + + const syncSearch = syncSearchStrategyProvider({ + core: mockCoreStart, + getSearchStrategy: jest.fn(), + }); + const request = { serverStrategy: SYNC_SEARCH_STRATEGY }; + + const loadingCount$ = mockCoreStart.http.addLoadingCountSource.mock.calls[0][0]; + loadingCount$.subscribe(value => receivedLoadingCountValues.push(value)); + + await syncSearch.search(request, {}).toPromise(); + + expect(receivedLoadingCountValues).toEqual(expectedLoadingCountValues); + }); + + it('increments and decrements loading count on failure', async () => { + expect.assertions(1); + const expectedLoadingCountValues = [0, 1, 0]; + const receivedLoadingCountValues: number[] = []; + + mockCoreStart.http.fetch.mockRejectedValueOnce('error'); + + const syncSearch = syncSearchStrategyProvider({ + core: mockCoreStart, + getSearchStrategy: jest.fn(), + }); + const request = { serverStrategy: SYNC_SEARCH_STRATEGY }; + + const loadingCount$ = mockCoreStart.http.addLoadingCountSource.mock.calls[0][0]; + loadingCount$.subscribe(value => receivedLoadingCountValues.push(value)); + + try { + await syncSearch.search(request, {}).toPromise(); + } catch (e) { + expect(receivedLoadingCountValues).toEqual(expectedLoadingCountValues); + } + }); }); diff --git a/src/plugins/data/public/search/sync_search_strategy.ts b/src/plugins/data/public/search/sync_search_strategy.ts index c2cc180af546e..860ce593ae217 100644 --- a/src/plugins/data/public/search/sync_search_strategy.ts +++ b/src/plugins/data/public/search/sync_search_strategy.ts @@ -18,7 +18,8 @@ */ import { BehaviorSubject, from } from 'rxjs'; -import { IKibanaSearchRequest, IKibanaSearchResponse } from '../../common/search'; +import { finalize } from 'rxjs/operators'; +import { IKibanaSearchRequest } from '../../common/search'; import { ISearch, ISearchOptions } from './i_search'; import { TSearchStrategyProvider, ISearchStrategy, ISearchContext } from './types'; @@ -40,16 +41,14 @@ export const syncSearchStrategyProvider: TSearchStrategyProvider { loadingCount$.next(loadingCount$.getValue() + 1); - const response: Promise = context.core.http.fetch({ - path: `/internal/search/${request.serverStrategy}`, - method: 'POST', - body: JSON.stringify(request), - signal: options.signal, - }); - - response.then(() => loadingCount$.next(loadingCount$.getValue() - 1)); - - return from(response); + return from( + context.core.http.fetch({ + path: `/internal/search/${request.serverStrategy}`, + method: 'POST', + body: JSON.stringify(request), + signal: options.signal, + }) + ).pipe(finalize(() => loadingCount$.next(loadingCount$.getValue() - 1))); }; return { search }; diff --git a/src/plugins/data/server/autocomplete/value_suggestions_route.ts b/src/plugins/data/server/autocomplete/value_suggestions_route.ts index f032890e98901..02a5e0921fe4f 100644 --- a/src/plugins/data/server/autocomplete/value_suggestions_route.ts +++ b/src/plugins/data/server/autocomplete/value_suggestions_route.ts @@ -23,6 +23,7 @@ import { IRouter } from 'kibana/server'; import { IFieldType, Filter } from '../index'; import { findIndexPatternById, getFieldByName } from '../index_patterns'; +import { getRequestAbortedSignal } from '../lib'; export function registerValueSuggestionsRoute(router: IRouter) { router.post( @@ -50,6 +51,7 @@ export function registerValueSuggestionsRoute(router: IRouter) { const { field: fieldName, query, boolFilter } = request.body; const { index } = request.params; const { dataClient } = context.core.elasticsearch; + const signal = getRequestAbortedSignal(request.events.aborted$); const autocompleteSearchOptions = { timeout: await uiSettings.get('kibana.autocompleteTimeout'), @@ -62,7 +64,7 @@ export function registerValueSuggestionsRoute(router: IRouter) { const body = await getBody(autocompleteSearchOptions, field || fieldName, query, boolFilter); try { - const result = await dataClient.callAsCurrentUser('search', { index, body }); + const result = await dataClient.callAsCurrentUser('search', { index, body }, { signal }); const buckets: any[] = get(result, 'aggregations.suggestions.buckets') || diff --git a/src/plugins/data/server/lib/get_request_aborted_signal.test.ts b/src/plugins/data/server/lib/get_request_aborted_signal.test.ts new file mode 100644 index 0000000000000..3c1e20dbcb158 --- /dev/null +++ b/src/plugins/data/server/lib/get_request_aborted_signal.test.ts @@ -0,0 +1,45 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Subject } from 'rxjs'; +import { getRequestAbortedSignal } from './get_request_aborted_signal'; + +describe('abortableRequestHandler', () => { + jest.useFakeTimers(); + + it('should call abort if disconnected', () => { + const abortedSubject = new Subject(); + const aborted$ = abortedSubject.asObservable(); + const onAborted = jest.fn(); + + const signal = getRequestAbortedSignal(aborted$); + signal.addEventListener('abort', onAborted); + + // Shouldn't be aborted or call onAborted prior to disconnecting + expect(signal.aborted).toBe(false); + expect(onAborted).not.toBeCalled(); + + abortedSubject.next(); + jest.runAllTimers(); + + // Should be aborted and call onAborted after disconnecting + expect(signal.aborted).toBe(true); + expect(onAborted).toBeCalled(); + }); +}); diff --git a/src/plugins/data/server/lib/get_request_aborted_signal.ts b/src/plugins/data/server/lib/get_request_aborted_signal.ts new file mode 100644 index 0000000000000..d1541f1df9384 --- /dev/null +++ b/src/plugins/data/server/lib/get_request_aborted_signal.ts @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Observable } from 'rxjs'; +// @ts-ignore not typed +import { AbortController } from 'abortcontroller-polyfill/dist/cjs-ponyfill'; + +/** + * A simple utility function that returns an `AbortSignal` corresponding to an `AbortController` + * which aborts when the given request is aborted. + * @param aborted$ The observable of abort events (usually `request.events.aborted$`) + */ +export function getRequestAbortedSignal(aborted$: Observable): AbortSignal { + const controller = new AbortController(); + aborted$.subscribe(() => controller.abort()); + return controller.signal; +} diff --git a/src/plugins/data/server/lib/index.ts b/src/plugins/data/server/lib/index.ts new file mode 100644 index 0000000000000..a2af456846e14 --- /dev/null +++ b/src/plugins/data/server/lib/index.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { getRequestAbortedSignal } from './get_request_aborted_signal'; diff --git a/src/plugins/data/server/search/routes.ts b/src/plugins/data/server/search/routes.ts index 6f726771c41b2..11879d14931ae 100644 --- a/src/plugins/data/server/search/routes.ts +++ b/src/plugins/data/server/search/routes.ts @@ -19,6 +19,7 @@ import { schema } from '@kbn/config-schema'; import { IRouter } from '../../../../core/server'; +import { getRequestAbortedSignal } from '../lib'; export function registerSearchRoute(router: IRouter): void { router.post( @@ -35,8 +36,10 @@ export function registerSearchRoute(router: IRouter): void { async (context, request, res) => { const searchRequest = request.body; const strategy = request.params.strategy; + const signal = getRequestAbortedSignal(request.events.aborted$); + try { - const response = await context.search!.search(searchRequest, {}, strategy); + const response = await context.search!.search(searchRequest, { signal }, strategy); return res.ok({ body: response }); } catch (err) { return res.customError({ From ca5fb7fb01256861cca9d897e628f11a17bc68fb Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 25 Feb 2020 15:56:28 -0500 Subject: [PATCH 071/123] Use links instead of click handlers when switching spaces (#57730) * use links instead of click handlers when switching spaces * remove unused imports * remove use of deprecated injectedMetadata service * simplify SpacesManager constructor Co-authored-by: Elastic Machine --- x-pack/plugins/spaces/common/index.ts | 2 +- .../nav_control/components/spaces_menu.tsx | 6 ++--- .../spaces/public/nav_control/nav_control.tsx | 1 + .../nav_control/nav_control_popover.test.tsx | 2 ++ .../nav_control/nav_control_popover.tsx | 7 ++--- x-pack/plugins/spaces/public/plugin.tsx | 3 +-- .../components/space_card.test.tsx | 27 ++++++++++++++----- .../space_selector/components/space_card.tsx | 9 ++++--- .../components/space_cards.test.tsx | 2 +- .../space_selector/components/space_cards.tsx | 12 +++------ .../space_selector/space_selector.test.tsx | 8 ++++-- .../public/space_selector/space_selector.tsx | 7 ++--- .../space_selector/space_selector_app.tsx | 5 +++- .../spaces_manager/spaces_manager.mock.ts | 1 - .../spaces_manager/spaces_manager.test.ts | 12 ++++----- .../public/spaces_manager/spaces_manager.ts | 12 ++++----- 16 files changed, 62 insertions(+), 54 deletions(-) diff --git a/x-pack/plugins/spaces/common/index.ts b/x-pack/plugins/spaces/common/index.ts index c1f0f8bd3ece4..703722fcf8f52 100644 --- a/x-pack/plugins/spaces/common/index.ts +++ b/x-pack/plugins/spaces/common/index.ts @@ -5,5 +5,5 @@ */ export { isReservedSpace } from './is_reserved_space'; -export { MAX_SPACE_INITIALS, SPACE_SEARCH_COUNT_THRESHOLD } from './constants'; +export { MAX_SPACE_INITIALS, SPACE_SEARCH_COUNT_THRESHOLD, ENTER_SPACE_PATH } from './constants'; export { addSpaceIdToPath, getSpaceIdFromPath } from './lib/spaces_url_parser'; diff --git a/x-pack/plugins/spaces/public/nav_control/components/spaces_menu.tsx b/x-pack/plugins/spaces/public/nav_control/components/spaces_menu.tsx index 59656333f865e..cdfbc9bbe2683 100644 --- a/x-pack/plugins/spaces/public/nav_control/components/spaces_menu.tsx +++ b/x-pack/plugins/spaces/public/nav_control/components/spaces_menu.tsx @@ -14,7 +14,7 @@ import { import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import React, { Component, ReactElement } from 'react'; import { Capabilities, ApplicationStart } from 'src/core/public'; -import { SPACE_SEARCH_COUNT_THRESHOLD } from '../../../common/constants'; +import { addSpaceIdToPath, SPACE_SEARCH_COUNT_THRESHOLD, ENTER_SPACE_PATH } from '../../../common'; import { Space } from '../../../common/model/space'; import { ManageSpacesButton } from './manage_spaces_button'; import { SpaceAvatar } from '../../space_avatar'; @@ -23,7 +23,7 @@ interface Props { id: string; spaces: Space[]; isLoading: boolean; - onSelectSpace: (space: Space) => void; + serverBasePath: string; onManageSpacesClick: () => void; intl: InjectedIntl; capabilities: Capabilities; @@ -184,7 +184,7 @@ class SpacesMenuUI extends Component { diff --git a/x-pack/plugins/spaces/public/nav_control/nav_control.tsx b/x-pack/plugins/spaces/public/nav_control/nav_control.tsx index 53d7038cec4d5..4d7af256822c8 100644 --- a/x-pack/plugins/spaces/public/nav_control/nav_control.tsx +++ b/x-pack/plugins/spaces/public/nav_control/nav_control.tsx @@ -23,6 +23,7 @@ export function initSpacesNavControl(spacesManager: SpacesManager, core: CoreSta { const wrapper = shallow( { const wrapper = mountWithIntl( { id={popoutContentId} spaces={this.state.spaces} isLoading={this.state.loading} - onSelectSpace={this.onSelectSpace} + serverBasePath={this.props.serverBasePath} onManageSpacesClick={this.toggleSpaceSelector} capabilities={this.props.capabilities} navigateToApp={this.props.navigateToApp} @@ -175,8 +176,4 @@ export class NavControlPopover extends Component { showSpaceSelector: false, }); }; - - private onSelectSpace = (space: Space) => { - this.props.spacesManager.changeSelectedSpace(space); - }; } diff --git a/x-pack/plugins/spaces/public/plugin.tsx b/x-pack/plugins/spaces/public/plugin.tsx index 73dae84c1873b..44215ec538002 100644 --- a/x-pack/plugins/spaces/public/plugin.tsx +++ b/x-pack/plugins/spaces/public/plugin.tsx @@ -43,8 +43,7 @@ export class SpacesPlugin implements Plugin { const space = { @@ -16,21 +17,33 @@ test('it renders without crashing', () => { disabledFeatures: [], }; - shallow(); + shallow(); }); -test('it is clickable', () => { +test('links to the indicated space', () => { const space = { - id: '', + id: 'some-space', name: 'space name', description: 'space description', disabledFeatures: [], }; - const clickHandler = jest.fn(); + const wrapper = mount(); + expect(wrapper.find(EuiCard).props()).toMatchObject({ + href: '/server-base-path/s/some-space/spaces/enter', + }); +}); - const wrapper = mount(); - wrapper.find('button').simulate('click'); +test('links to the default space too', () => { + const space = { + id: 'default', + name: 'default space', + description: 'space description', + disabledFeatures: [], + }; - expect(clickHandler).toHaveBeenCalledTimes(1); + const wrapper = mount(); + expect(wrapper.find(EuiCard).props()).toMatchObject({ + href: '/server-base-path/spaces/enter', + }); }); diff --git a/x-pack/plugins/spaces/public/space_selector/components/space_card.tsx b/x-pack/plugins/spaces/public/space_selector/components/space_card.tsx index f898ba87c60bd..7a056427fb166 100644 --- a/x-pack/plugins/spaces/public/space_selector/components/space_card.tsx +++ b/x-pack/plugins/spaces/public/space_selector/components/space_card.tsx @@ -6,15 +6,16 @@ import { EuiCard } from '@elastic/eui'; import React from 'react'; -import { Space } from '../../../common/model/space'; +import { addSpaceIdToPath, ENTER_SPACE_PATH } from '../../../common'; import { SpaceAvatar } from '../../space_avatar'; +import { Space } from '../..'; interface Props { space: Space; - onClick: () => void; + serverBasePath: string; } export const SpaceCard = (props: Props) => { - const { space, onClick } = props; + const { serverBasePath, space } = props; return ( { icon={renderSpaceAvatar(space)} title={space.name} description={renderSpaceDescription(space)} - onClick={onClick} + href={addSpaceIdToPath(serverBasePath, space.id, ENTER_SPACE_PATH)} /> ); }; diff --git a/x-pack/plugins/spaces/public/space_selector/components/space_cards.test.tsx b/x-pack/plugins/spaces/public/space_selector/components/space_cards.test.tsx index 07b85114e3c8f..8de22bcbe235f 100644 --- a/x-pack/plugins/spaces/public/space_selector/components/space_cards.test.tsx +++ b/x-pack/plugins/spaces/public/space_selector/components/space_cards.test.tsx @@ -16,5 +16,5 @@ test('it renders without crashing', () => { disabledFeatures: [], }; - shallow(); + shallow(); }); diff --git a/x-pack/plugins/spaces/public/space_selector/components/space_cards.tsx b/x-pack/plugins/spaces/public/space_selector/components/space_cards.tsx index 7c4084d36b21d..b480cf524304f 100644 --- a/x-pack/plugins/spaces/public/space_selector/components/space_cards.tsx +++ b/x-pack/plugins/spaces/public/space_selector/components/space_cards.tsx @@ -11,7 +11,7 @@ import { SpaceCard } from './space_card'; interface Props { spaces: Space[]; - onSpaceSelect: (space: Space) => void; + serverBasePath: string; } export class SpaceCards extends Component { @@ -25,15 +25,9 @@ export class SpaceCards extends Component { ); } - public renderSpace = (space: Space) => ( + private renderSpace = (space: Space) => ( - + ); - - public createSpaceClickHandler = (space: Space) => { - return () => { - this.props.onSpaceSelect(space); - }; - }; } diff --git a/x-pack/plugins/spaces/public/space_selector/space_selector.test.tsx b/x-pack/plugins/spaces/public/space_selector/space_selector.test.tsx index c8173de1661be..112a8a9a0a685 100644 --- a/x-pack/plugins/spaces/public/space_selector/space_selector.test.tsx +++ b/x-pack/plugins/spaces/public/space_selector/space_selector.test.tsx @@ -18,7 +18,9 @@ function getSpacesManager(spaces: Space[] = []) { test('it renders without crashing', () => { const spacesManager = getSpacesManager(); - const component = shallowWithIntl(); + const component = shallowWithIntl( + + ); expect(component).toMatchSnapshot(); }); @@ -34,7 +36,9 @@ test('it queries for spaces when loaded', () => { const spacesManager = getSpacesManager(spaces); - shallowWithIntl(); + shallowWithIntl( + + ); return Promise.resolve().then(() => { expect(spacesManager.getSpaces).toHaveBeenCalledTimes(1); diff --git a/x-pack/plugins/spaces/public/space_selector/space_selector.tsx b/x-pack/plugins/spaces/public/space_selector/space_selector.tsx index b63de399b95c9..9289784b9f95f 100644 --- a/x-pack/plugins/spaces/public/space_selector/space_selector.tsx +++ b/x-pack/plugins/spaces/public/space_selector/space_selector.tsx @@ -30,6 +30,7 @@ import { SpacesManager } from '../spaces_manager'; interface Props { spacesManager: SpacesManager; + serverBasePath: string; } interface State { @@ -129,7 +130,7 @@ export class SpaceSelector extends Component { {this.state.loading && } {!this.state.loading && ( - + )} {!this.state.loading && filteredSpaces.length === 0 && ( @@ -179,10 +180,6 @@ export class SpaceSelector extends Component { searchTerm: searchTerm.trim().toLowerCase(), }); }; - - public onSelectSpace = (space: Space) => { - this.props.spacesManager.changeSelectedSpace(space); - }; } export const renderSpaceSelectorApp = (i18nStart: CoreStart['i18n'], el: Element, props: Props) => { diff --git a/x-pack/plugins/spaces/public/space_selector/space_selector_app.tsx b/x-pack/plugins/spaces/public/space_selector/space_selector_app.tsx index 29ead8d34994d..6fab1767e4b6d 100644 --- a/x-pack/plugins/spaces/public/space_selector/space_selector_app.tsx +++ b/x-pack/plugins/spaces/public/space_selector/space_selector_app.tsx @@ -29,7 +29,10 @@ export const spaceSelectorApp = Object.freeze({ getStartServices(), import('./space_selector'), ]); - return renderSpaceSelectorApp(coreStart.i18n, params.element, { spacesManager }); + return renderSpaceSelectorApp(coreStart.i18n, params.element, { + spacesManager, + serverBasePath: coreStart.http.basePath.serverBasePath, + }); }, }); }, diff --git a/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.mock.ts b/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.mock.ts index 56879af33916f..6186ac7fd93be 100644 --- a/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.mock.ts +++ b/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.mock.ts @@ -20,7 +20,6 @@ function createSpacesManagerMock() { copySavedObjects: jest.fn().mockResolvedValue(undefined), resolveCopySavedObjectsErrors: jest.fn().mockResolvedValue(undefined), redirectToSpaceSelector: jest.fn().mockResolvedValue(undefined), - changeSelectedSpace: jest.fn(), } as unknown) as jest.Mocked; } diff --git a/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.test.ts b/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.test.ts index f89bfc32a69e6..508669361c23f 100644 --- a/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.test.ts +++ b/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.test.ts @@ -12,14 +12,14 @@ describe('SpacesManager', () => { describe('#constructor', () => { it('attempts to retrieve the active space', () => { const coreStart = coreMock.createStart(); - new SpacesManager('/server-base-path', coreStart.http); + new SpacesManager(coreStart.http); expect(coreStart.http.get).toHaveBeenCalledWith('/internal/spaces/_active_space'); }); it('does not retrieve the active space if on an anonymous path', () => { const coreStart = coreMock.createStart(); coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(true); - new SpacesManager('/server-base-path', coreStart.http); + new SpacesManager(coreStart.http); expect(coreStart.http.get).not.toHaveBeenCalled(); }); }); @@ -31,7 +31,7 @@ describe('SpacesManager', () => { id: 'my-space', name: 'my space', }); - const spacesManager = new SpacesManager('/server-base-path', coreStart.http); + const spacesManager = new SpacesManager(coreStart.http); expect(coreStart.http.get).toHaveBeenCalledWith('/internal/spaces/_active_space'); await nextTick(); @@ -47,7 +47,7 @@ describe('SpacesManager', () => { it('throws if on an anonymous path', () => { const coreStart = coreMock.createStart(); coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(true); - const spacesManager = new SpacesManager('/server-base-path', coreStart.http); + const spacesManager = new SpacesManager(coreStart.http); expect(coreStart.http.get).not.toHaveBeenCalled(); expect(() => spacesManager.getActiveSpace()).toThrowErrorMatchingInlineSnapshot( @@ -67,7 +67,7 @@ describe('SpacesManager', () => { name: 'my other space', }); - const spacesManager = new SpacesManager('/server-base-path', coreStart.http); + const spacesManager = new SpacesManager(coreStart.http); expect(coreStart.http.get).toHaveBeenCalledWith('/internal/spaces/_active_space'); await nextTick(); @@ -95,7 +95,7 @@ describe('SpacesManager', () => { name: 'my space', }); - const spacesManager = new SpacesManager('/server-base-path', coreStart.http); + const spacesManager = new SpacesManager(coreStart.http); expect(() => spacesManager.getActiveSpace({ forceRefresh: true }) diff --git a/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.ts b/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.ts index e151dcd4f9368..cc3f51b1850de 100644 --- a/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.ts +++ b/x-pack/plugins/spaces/public/spaces_manager/spaces_manager.ts @@ -9,16 +9,18 @@ import { HttpSetup } from 'src/core/public'; import { SavedObjectsManagementRecord } from 'src/legacy/core_plugins/management/public'; import { Space } from '../../common/model/space'; import { GetSpacePurpose } from '../../common/model/types'; -import { ENTER_SPACE_PATH } from '../../common/constants'; import { CopySavedObjectsToSpaceResponse } from '../copy_saved_objects_to_space/types'; -import { addSpaceIdToPath } from '../../common'; export class SpacesManager { private activeSpace$: BehaviorSubject = new BehaviorSubject(null); + private readonly serverBasePath: string; + public readonly onActiveSpaceChange$: Observable; - constructor(private readonly serverBasePath: string, private readonly http: HttpSetup) { + constructor(private readonly http: HttpSetup) { + this.serverBasePath = http.basePath.serverBasePath; + this.onActiveSpaceChange$ = this.activeSpace$ .asObservable() .pipe(skipWhile((v: Space | null) => v == null)) as Observable; @@ -99,10 +101,6 @@ export class SpacesManager { }); } - public async changeSelectedSpace(space: Space) { - window.location.href = addSpaceIdToPath(this.serverBasePath, space.id, ENTER_SPACE_PATH); - } - public redirectToSpaceSelector() { window.location.href = `${this.serverBasePath}/spaces/space_selector`; } From 0e2363615d62e0e27cf8bcce053a5ea80b6acf2e Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 25 Feb 2020 13:59:04 -0700 Subject: [PATCH 072/123] Fix flaky jest test (#58402) * Revert "Temporarily removes kbn-optimizer cache key tests (#58318)" This reverts commit e64eff0a3d5fde205256ab74b731a63766822f9a. * [kbn-optmizer] avoid mocking fs exports * overwrite ciGroup script to support jest in flaky testing job * limit jest workers to 3 so that concurrent runners have space to operate * Revert "limit jest workers to 3 so that concurrent runners have space to operate" This reverts commit 1a2f882f6d0b37366b0accc6dbb8bc2b42a5fc3f. * Revert "overwrite ciGroup script to support jest in flaky testing job" This reverts commit 548db6172213858691c3b93dc77cb8fd48d4fc3c. --- .../src/optimizer/cache_keys.test.ts | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 packages/kbn-optimizer/src/optimizer/cache_keys.test.ts diff --git a/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts b/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts new file mode 100644 index 0000000000000..7750f9145667e --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts @@ -0,0 +1,208 @@ +/* + * 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 Path from 'path'; + +import jestDiff from 'jest-diff'; +import { REPO_ROOT, createAbsolutePathSerializer } from '@kbn/dev-utils'; + +import { reformatJestDiff, getOptimizerCacheKey, diffCacheKey } from './cache_keys'; +import { OptimizerConfig } from './optimizer_config'; + +jest.mock('./get_changes.ts', () => ({ + getChanges: async () => + new Map([ + ['/foo/bar/a', 'modified'], + ['/foo/bar/b', 'modified'], + ['/foo/bar/c', 'deleted'], + ]), +})); + +jest.mock('./get_mtimes.ts', () => ({ + getMtimes: async (paths: string[]) => new Map(paths.map(path => [path, 12345])), +})); + +jest.mock('execa'); + +jest.mock('fs', () => { + const realFs = jest.requireActual('fs'); + return { + ...realFs, + readFile: jest.fn(realFs.readFile), + }; +}); + +expect.addSnapshotSerializer(createAbsolutePathSerializer()); + +jest.requireMock('execa').mockImplementation(async (cmd: string, args: string[], opts: object) => { + expect(cmd).toBe('git'); + expect(args).toEqual([ + 'log', + '-n', + '1', + '--pretty=format:%H', + '--', + expect.stringContaining('kbn-optimizer'), + ]); + expect(opts).toEqual({ + cwd: REPO_ROOT, + }); + + return { + stdout: '', + }; +}); + +describe('getOptimizerCacheKey()', () => { + it('uses latest commit, bootstrap cache, and changed files to create unique value', async () => { + jest + .requireMock('fs') + .readFile.mockImplementation( + (path: string, enc: string, cb: (err: null, file: string) => void) => { + expect(path).toBe( + Path.resolve(REPO_ROOT, 'packages/kbn-optimizer/target/.bootstrap-cache') + ); + expect(enc).toBe('utf8'); + cb(null, ''); + } + ); + + const config = OptimizerConfig.create({ + repoRoot: REPO_ROOT, + }); + + await expect(getOptimizerCacheKey(config)).resolves.toMatchInlineSnapshot(` + Object { + "bootstrap": "", + "deletedPaths": Array [ + "/foo/bar/c", + ], + "lastCommit": "", + "modifiedTimes": Object { + "/foo/bar/a": 12345, + "/foo/bar/b": 12345, + }, + "workerConfig": Object { + "browserslistEnv": "dev", + "cache": true, + "dist": false, + "optimizerCacheKey": "♻", + "profileWebpack": false, + "repoRoot": , + "watch": false, + }, + } + `); + }); +}); + +describe('diffCacheKey()', () => { + it('returns undefined if values are equal', () => { + expect(diffCacheKey('1', '1')).toBe(undefined); + expect(diffCacheKey(1, 1)).toBe(undefined); + expect(diffCacheKey(['1', '2', { a: 'b' }], ['1', '2', { a: 'b' }])).toBe(undefined); + expect( + diffCacheKey( + { + a: '1', + b: '2', + }, + { + b: '2', + a: '1', + } + ) + ).toBe(undefined); + }); + + it('returns a diff if the values are different', () => { + expect(diffCacheKey(['1', '2', { a: 'b' }], ['1', '2', { b: 'a' }])).toMatchInlineSnapshot(` + "- Expected + + Received + +  Array [ +  \\"1\\", +  \\"2\\", +  Object { + - \\"a\\": \\"b\\", + + \\"b\\": \\"a\\", +  }, +  ]" + `); + expect( + diffCacheKey( + { + a: '1', + b: '1', + }, + { + b: '2', + a: '2', + } + ) + ).toMatchInlineSnapshot(` + "- Expected + + Received + +  Object { + - \\"a\\": \\"1\\", + - \\"b\\": \\"1\\", + + \\"a\\": \\"2\\", + + \\"b\\": \\"2\\", +  }" + `); + }); +}); + +describe('reformatJestDiff()', () => { + it('reformats large jestDiff output to focus on the changed lines', () => { + const diff = jestDiff( + { + a: ['1', '1', '1', '1', '1', '1', '1', '2', '1', '1', '1', '1', '1', '1', '1', '1', '1'], + }, + { + b: ['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '1', '1', '1', '1'], + } + ); + + expect(reformatJestDiff(diff)).toMatchInlineSnapshot(` + "- Expected + + Received + +  Object { + - \\"a\\": Array [ + + \\"b\\": Array [ +  \\"1\\", +  \\"1\\", +  ... +  \\"1\\", +  \\"1\\", + - \\"2\\", +  \\"1\\", +  \\"1\\", +  ... +  \\"1\\", +  \\"1\\", + + \\"2\\", +  \\"1\\", +  \\"1\\", +  ..." + `); + }); +}); From 2501919a8a191cc127973b3789bf588229e2071c Mon Sep 17 00:00:00 2001 From: Ryland Herrick Date: Tue, 25 Feb 2020 15:33:49 -0600 Subject: [PATCH 073/123] Remove support of HEAD request in signals index route (#58489) Until these are officially supported in new platform, it's best to not rely on this behavior. We can achieve roughly the same functionality with a GET request. Modifies the existing script accordingly, in case anyone's still using it. Co-authored-by: Elastic Machine --- .../routes/index/read_index_route.ts | 25 ++++++------------- .../scripts/signal_index_exists.sh | 4 +-- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/index/read_index_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/index/read_index_route.ts index 41be42f7c0fe1..26a6c790ceef9 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/index/read_index_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/index/read_index_route.ts @@ -36,25 +36,14 @@ export const createReadIndexRoute = ( const indexExists = await getIndexExists(callCluster, index); if (indexExists) { - // head request is used for if you want to get if the index exists - // or not and it will return a content-length: 0 along with either a 200 or 404 - // depending on if the index exists or not. - if (request.method.toLowerCase() === 'head') { - return headers.response().code(200); - } else { - return headers.response({ name: index }).code(200); - } + return headers.response({ name: index }).code(200); } else { - if (request.method.toLowerCase() === 'head') { - return headers.response().code(404); - } else { - return headers - .response({ - message: 'index for this space does not exist', - status_code: 404, - }) - .code(404); - } + return headers + .response({ + message: 'index for this space does not exist', + status_code: 404, + }) + .code(404); } } catch (err) { const error = transformError(err); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/signal_index_exists.sh b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/signal_index_exists.sh index b4a494a102b54..ec3e0595c7b08 100755 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/signal_index_exists.sh +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/signal_index_exists.sh @@ -10,7 +10,7 @@ set -e ./check_env_variables.sh # Example: ./signal_index_exists.sh -curl -s -k --head \ +curl -s -k -f \ -H 'Content-Type: application/json' \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - ${KIBANA_URL}${SPACE_URL}/api/detection_engine/index + ${KIBANA_URL}${SPACE_URL}/api/detection_engine/index > /dev/null From 87f6cd115252e4fa6914c1fc767ab58650c3e253 Mon Sep 17 00:00:00 2001 From: Andrew Cholakian Date: Tue, 25 Feb 2020 16:40:06 -0600 Subject: [PATCH 074/123] [Uptime] Show only total in snapshot heading (#58376) This fixes a number of design issues. Fixes https://github.com/elastic/kibana/issues/58372 --- .../__snapshots__/snapshot.test.tsx.snap | 1 - .../snapshot_heading.test.tsx.snap | 12 ++++-- .../__tests__/snapshot_heading.test.tsx | 6 +-- .../__snapshots__/chart_wrapper.test.tsx.snap | 2 - .../charts/__tests__/chart_wrapper.test.tsx | 8 ++-- .../public/components/functional/snapshot.tsx | 7 ++-- .../functional/snapshot_heading.tsx | 39 ++++++------------- .../translations/translations/ja-JP.json | 3 -- .../translations/translations/zh-CN.json | 3 -- 9 files changed, 31 insertions(+), 50 deletions(-) diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/snapshot.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/snapshot.test.tsx.snap index ebbd8a4ac56a8..db41dfb0b04c4 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/snapshot.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/snapshot.test.tsx.snap @@ -5,7 +5,6 @@ exports[`Snapshot component renders without errors 1`] = ` loading={false} >

- All monitors are up + 23 + + Monitors

`; @@ -15,7 +17,9 @@ exports[`SnapshotHeading renders custom heading for no monitors 1`] = ` size="s" >

- No monitors found + 0 + + Monitors

`; @@ -25,7 +29,9 @@ exports[`SnapshotHeading renders standard heading for valid counts 1`] = ` size="s" >

- 3/17 monitors are down + 17 + + Monitors

`; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/snapshot_heading.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/snapshot_heading.test.tsx index 5ddef3d0aabd1..70d082b26d653 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/snapshot_heading.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/snapshot_heading.test.tsx @@ -10,17 +10,17 @@ import { SnapshotHeading } from '../snapshot_heading'; describe('SnapshotHeading', () => { it('renders custom heading for no down monitors', () => { - const wrapper = shallowWithIntl(); + const wrapper = shallowWithIntl(); expect(wrapper).toMatchSnapshot(); }); it('renders standard heading for valid counts', () => { - const wrapper = shallowWithIntl(); + const wrapper = shallowWithIntl(); expect(wrapper).toMatchSnapshot(); }); it('renders custom heading for no monitors', () => { - const wrapper = shallowWithIntl(); + const wrapper = shallowWithIntl(); expect(wrapper).toMatchSnapshot(); }); }); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/chart_wrapper.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/chart_wrapper.test.tsx.snap index c1b5970f6456c..71690432fd01b 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/chart_wrapper.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/chart_wrapper.test.tsx.snap @@ -114,7 +114,6 @@ exports[`ChartWrapper component renders the component with loading false 1`] = ` } > { it('renders the component with loading false', () => { const component = shallowWithIntl( - + @@ -29,7 +29,7 @@ describe('ChartWrapper component', () => { it('renders the component with loading true', () => { const component = shallowWithIntl( - + @@ -40,7 +40,7 @@ describe('ChartWrapper component', () => { it('mounts the component with loading true or false', async () => { const component = mount( - + @@ -62,7 +62,7 @@ describe('ChartWrapper component', () => { it('mounts the component with chart when loading true or false', async () => { const component = mount( - + diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/snapshot.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/snapshot.tsx index 8531cd1a3cc83..999ade9dccdd9 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/snapshot.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/snapshot.tsx @@ -6,7 +6,6 @@ import { EuiSpacer } from '@elastic/eui'; import React from 'react'; -import { get } from 'lodash'; import { DonutChart } from './charts'; import { ChartWrapper } from './charts/chart_wrapper'; import { SnapshotHeading } from './snapshot_heading'; @@ -28,11 +27,11 @@ interface SnapshotComponentProps { */ export const SnapshotComponent: React.FC = ({ count, height, loading }) => ( - (count, 'down', 0)} total={get(count, 'total', 0)} /> + (count, 'up', 0)} - down={get(count, 'down', 0)} + up={count.up} + down={count.down} height={SNAPSHOT_CHART_HEIGHT} width={SNAPSHOT_CHART_WIDTH} /> diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/snapshot_heading.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/snapshot_heading.tsx index 85d1294d4b064..308d6e19241c2 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/snapshot_heading.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/snapshot_heading.tsx @@ -8,32 +8,17 @@ import { EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -interface Props { - down: number; - total: number; -} +export const SnapshotHeading = ({ total }: { total: number }) => { + const monitorsText = + total === 1 + ? i18n.translate('xpack.uptime.snapshot.monitor', { defaultMessage: 'Monitor' }) + : i18n.translate('xpack.uptime.snapshot.monitors', { defaultMessage: 'Monitors' }); -const getMessage = (down: number, total: number): string => { - if (down === 0 && total > 0) { - return i18n.translate('xpack.uptime.snapshot.zeroDownMessage', { - defaultMessage: 'All monitors are up', - }); - } else if (down === 0 && total === 0) { - return i18n.translate('xpack.uptime.snapshot.noMonitorMessage', { - defaultMessage: 'No monitors found', - }); - } - return i18n.translate('xpack.uptime.snapshot.downCountsMessage', { - defaultMessage: '{down}/{total} monitors are down', - values: { - down, - total, - }, - }); + return ( + +

+ {total} {monitorsText} +

+
+ ); }; - -export const SnapshotHeading = ({ down, total }: Props) => ( - -

{getMessage(down, total)}

-
-); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index dc8d6343007b8..4a627d48c3cf0 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -12781,12 +12781,9 @@ "xpack.uptime.pingList.statusOptions.downStatusOptionLabel": "ダウン", "xpack.uptime.pingList.statusOptions.upStatusOptionLabel": "アップ", "xpack.uptime.pluginDescription": "アップタイム監視", - "xpack.uptime.snapshot.downCountsMessage": "{down}/{total} 個のモニターがダウンしています", "xpack.uptime.snapshot.noDataDescription": "申し訳ございませんが、ヒストグラムに利用可能なデータがありません", "xpack.uptime.snapshot.noDataTitle": "ヒストグラムデータがありません", - "xpack.uptime.snapshot.noMonitorMessage": "モニターが見つかりません", "xpack.uptime.snapshot.pingsOverTimeTitle": "一定時間のピング", - "xpack.uptime.snapshot.zeroDownMessage": "すべてのモニターが起動しています", "xpack.uptime.snapshotHistogram.description": "{startTime} から {endTime} までの期間のアップタイムステータスを表示する棒グラフです。", "xpack.uptime.snapshotHistogram.downMonitorsId": "ダウンモニター", "xpack.uptime.snapshotHistogram.series.downLabel": "ダウン", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index f6ef0140e385e..e0ef4a7a1ebdb 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -12781,12 +12781,9 @@ "xpack.uptime.pingList.statusOptions.downStatusOptionLabel": "关闭", "xpack.uptime.pingList.statusOptions.upStatusOptionLabel": "运行", "xpack.uptime.pluginDescription": "运行时间监测", - "xpack.uptime.snapshot.downCountsMessage": "{down}/{total} 个监测已关闭", "xpack.uptime.snapshot.noDataDescription": "抱歉,没有可用于该直方图的数据", "xpack.uptime.snapshot.noDataTitle": "没有可用的直方图数据", - "xpack.uptime.snapshot.noMonitorMessage": "未找到任何监测", "xpack.uptime.snapshot.pingsOverTimeTitle": "时移 Ping 数", - "xpack.uptime.snapshot.zeroDownMessage": "所有监测已启动", "xpack.uptime.snapshotHistogram.description": "显示从 {startTime} 到 {endTime} 的运行时间时移状态的条形图。", "xpack.uptime.snapshotHistogram.downMonitorsId": "已关闭监测", "xpack.uptime.snapshotHistogram.series.downLabel": "关闭", From ef80ebf1bb4b9b399b0fcb852e305c2f0db3c853 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 25 Feb 2020 15:57:40 -0700 Subject: [PATCH 075/123] [Search service] Add async search strategy (#53057) * Add async search strategy * Add async search * Fix async strategy and add tests * Move types to separate file * Revert changes to demo search * Update demo search strategy to use async * Add cancellation to search strategies * Add tests * Simplify async search strategy * Move loadingCount to search strategy * Update abort controller library * Bootstrap * Abort when the request is aborted * Add utility and update value suggestions route * Fix bad merge conflict * Update tests * Move to data_enhanced plugin * Remove bad merge * Revert switching abort controller libraries * Revert package.json in lib * Move to previous abort controller * Fix test to use fake timers to run debounced handlers * Revert changes to example plugin * Fix loading bar not going away when cancelling * Call getSearchStrategy instead of passing directly * Add async demo search strategy * Fix error with setting state * Update how aborting works * Fix type checks * Add test for loading count * Attempt to fix broken example test * Revert changes to test * Fix test * Update name to camelCase * Fix failing test * Don't require data_enhanced in example plugin Co-authored-by: Elastic Machine --- examples/demo_search/common/index.ts | 9 ++ examples/demo_search/kibana.json | 2 +- .../public/async_demo_search_strategy.ts | 69 ++++++++++ .../public/demo_search_strategy.ts | 2 +- examples/demo_search/public/plugin.ts | 17 ++- .../server/async_demo_search_strategy.ts | 60 +++++++++ examples/demo_search/server/plugin.ts | 17 ++- examples/search_explorer/kibana.json | 2 +- examples/search_explorer/package.json | 2 +- .../search_explorer/public/application.tsx | 6 + .../public/async_demo_strategy.tsx | 123 +++++++++++++++++ examples/search_explorer/public/do_search.tsx | 4 +- src/plugins/data/common/search/types.ts | 6 - .../search/es_search/es_search_strategy.ts | 10 +- src/plugins/data/public/search/index.ts | 2 +- .../data/server/search/create_api.test.ts | 2 +- src/plugins/data/server/search/create_api.ts | 11 +- .../search/i_route_handler_search_context.ts | 3 +- src/plugins/data/server/search/i_search.ts | 7 + .../data/server/search/i_search_strategy.ts | 3 +- src/plugins/data/server/search/routes.ts | 33 ++++- x-pack/plugins/data_enhanced/public/index.ts | 2 + x-pack/plugins/data_enhanced/public/plugin.ts | 8 +- .../search/async_search_strategy.test.ts | 125 ++++++++++++++++++ .../public/search/async_search_strategy.ts | 75 +++++++++++ .../data_enhanced/public/search/index.ts | 8 ++ .../data_enhanced/public/search/types.ts | 21 +++ 27 files changed, 601 insertions(+), 28 deletions(-) create mode 100644 examples/demo_search/public/async_demo_search_strategy.ts create mode 100644 examples/demo_search/server/async_demo_search_strategy.ts create mode 100644 examples/search_explorer/public/async_demo_strategy.tsx create mode 100644 x-pack/plugins/data_enhanced/public/search/async_search_strategy.test.ts create mode 100644 x-pack/plugins/data_enhanced/public/search/async_search_strategy.ts create mode 100644 x-pack/plugins/data_enhanced/public/search/index.ts create mode 100644 x-pack/plugins/data_enhanced/public/search/types.ts diff --git a/examples/demo_search/common/index.ts b/examples/demo_search/common/index.ts index 6587ee96ef61b..8ea8d6186ee82 100644 --- a/examples/demo_search/common/index.ts +++ b/examples/demo_search/common/index.ts @@ -20,6 +20,7 @@ import { IKibanaSearchRequest, IKibanaSearchResponse } from '../../../src/plugins/data/public'; export const DEMO_SEARCH_STRATEGY = 'DEMO_SEARCH_STRATEGY'; +export const ASYNC_DEMO_SEARCH_STRATEGY = 'ASYNC_DEMO_SEARCH_STRATEGY'; export interface IDemoRequest extends IKibanaSearchRequest { mood: string | 'sad' | 'happy'; @@ -29,3 +30,11 @@ export interface IDemoRequest extends IKibanaSearchRequest { export interface IDemoResponse extends IKibanaSearchResponse { greeting: string; } + +export interface IAsyncDemoRequest extends IKibanaSearchRequest { + fibonacciNumbers: number; +} + +export interface IAsyncDemoResponse extends IKibanaSearchResponse { + fibonacciSequence: number[]; +} diff --git a/examples/demo_search/kibana.json b/examples/demo_search/kibana.json index 0603706b07d1f..cb73274ed23f7 100644 --- a/examples/demo_search/kibana.json +++ b/examples/demo_search/kibana.json @@ -2,7 +2,7 @@ "id": "demoSearch", "version": "0.0.1", "kibanaVersion": "kibana", - "configPath": ["demo_search"], + "configPath": ["demoSearch"], "server": true, "ui": true, "requiredPlugins": ["data"], diff --git a/examples/demo_search/public/async_demo_search_strategy.ts b/examples/demo_search/public/async_demo_search_strategy.ts new file mode 100644 index 0000000000000..7a3f33ce05a75 --- /dev/null +++ b/examples/demo_search/public/async_demo_search_strategy.ts @@ -0,0 +1,69 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Observable } from 'rxjs'; +import { + ISearchContext, + TSearchStrategyProvider, + ISearchStrategy, +} from '../../../src/plugins/data/public'; + +import { ASYNC_DEMO_SEARCH_STRATEGY, IAsyncDemoResponse } from '../common'; +import { ASYNC_SEARCH_STRATEGY } from '../../../x-pack/plugins/data_enhanced/public'; + +/** + * This demo search strategy provider simply provides a shortcut for calling the DEMO_ASYNC_SEARCH_STRATEGY + * on the server side, without users having to pass it in explicitly, and it takes advantage of the + * already registered ASYNC_SEARCH_STRATEGY that exists on the client. + * + * so instead of callers having to do: + * + * ``` + * search( + * { ...request, serverStrategy: DEMO_ASYNC_SEARCH_STRATEGY }, + * options, + * ASYNC_SEARCH_STRATEGY + * ) as Observable, + *``` + + * They can instead just do + * + * ``` + * search(request, options, DEMO_ASYNC_SEARCH_STRATEGY); + * ``` + * + * and are ensured type safety in regard to the request and response objects. + * + * @param context - context supplied by other plugins. + * @param search - a search function to access other strategies that have already been registered. + */ +export const asyncDemoClientSearchStrategyProvider: TSearchStrategyProvider = ( + context: ISearchContext +): ISearchStrategy => { + const asyncStrategyProvider = context.getSearchStrategy(ASYNC_SEARCH_STRATEGY); + const { search } = asyncStrategyProvider(context); + return { + search: (request, options) => { + return search( + { ...request, serverStrategy: ASYNC_DEMO_SEARCH_STRATEGY }, + options + ) as Observable; + }, + }; +}; diff --git a/examples/demo_search/public/demo_search_strategy.ts b/examples/demo_search/public/demo_search_strategy.ts index cb2480c8a5f19..8dc2779a8544c 100644 --- a/examples/demo_search/public/demo_search_strategy.ts +++ b/examples/demo_search/public/demo_search_strategy.ts @@ -43,7 +43,7 @@ import { DEMO_SEARCH_STRATEGY, IDemoResponse } from '../common'; * ``` * context.search(request, options, DEMO_SEARCH_STRATEGY); * ``` - * + * * and are ensured type safety in regard to the request and response objects. * * @param context - context supplied by other plugins. diff --git a/examples/demo_search/public/plugin.ts b/examples/demo_search/public/plugin.ts index 62c912716e627..a2539cc7a21c5 100644 --- a/examples/demo_search/public/plugin.ts +++ b/examples/demo_search/public/plugin.ts @@ -19,9 +19,16 @@ import { DataPublicPluginSetup } from '../../../src/plugins/data/public'; import { Plugin, CoreSetup } from '../../../src/core/public'; -import { DEMO_SEARCH_STRATEGY } from '../common'; +import { + DEMO_SEARCH_STRATEGY, + IDemoRequest, + IDemoResponse, + ASYNC_DEMO_SEARCH_STRATEGY, + IAsyncDemoRequest, + IAsyncDemoResponse, +} from '../common'; import { demoClientSearchStrategyProvider } from './demo_search_strategy'; -import { IDemoRequest, IDemoResponse } from '../common'; +import { asyncDemoClientSearchStrategyProvider } from './async_demo_search_strategy'; interface DemoDataSearchSetupDependencies { data: DataPublicPluginSetup; @@ -39,10 +46,12 @@ interface DemoDataSearchSetupDependencies { declare module '../../../src/plugins/data/public' { export interface IRequestTypesMap { [DEMO_SEARCH_STRATEGY]: IDemoRequest; + [ASYNC_DEMO_SEARCH_STRATEGY]: IAsyncDemoRequest; } export interface IResponseTypesMap { [DEMO_SEARCH_STRATEGY]: IDemoResponse; + [ASYNC_DEMO_SEARCH_STRATEGY]: IAsyncDemoResponse; } } @@ -52,6 +61,10 @@ export class DemoDataPlugin implements Plugin { DEMO_SEARCH_STRATEGY, demoClientSearchStrategyProvider ); + deps.data.search.registerSearchStrategyProvider( + ASYNC_DEMO_SEARCH_STRATEGY, + asyncDemoClientSearchStrategyProvider + ); } public start() {} diff --git a/examples/demo_search/server/async_demo_search_strategy.ts b/examples/demo_search/server/async_demo_search_strategy.ts new file mode 100644 index 0000000000000..d2d40891a5d93 --- /dev/null +++ b/examples/demo_search/server/async_demo_search_strategy.ts @@ -0,0 +1,60 @@ +/* + * 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 { TSearchStrategyProvider } from '../../../src/plugins/data/server'; +import { ASYNC_DEMO_SEARCH_STRATEGY } from '../common'; + +function getFibonacciSequence(n = 0) { + const beginning = [0, 1].slice(0, n); + return Array(Math.max(0, n)) + .fill(null) + .reduce((sequence, value, i) => { + if (i < 2) return sequence; + return [...sequence, sequence[i - 1] + sequence[i - 2]]; + }, beginning); +} + +const generateId = (() => { + let id = 0; + return () => `${id++}`; +})(); + +const loadedMap = new Map(); +const totalMap = new Map(); + +export const asyncDemoSearchStrategyProvider: TSearchStrategyProvider = () => { + return { + search: async request => { + const id = request.id ?? generateId(); + + const loaded = (loadedMap.get(id) ?? 0) + 1; + loadedMap.set(id, loaded); + + const total = request.fibonacciNumbers ?? totalMap.get(id); + totalMap.set(id, total); + + const fibonacciSequence = getFibonacciSequence(loaded); + return { id, total, loaded, fibonacciSequence }; + }, + cancel: async id => { + loadedMap.delete(id); + totalMap.delete(id); + }, + }; +}; diff --git a/examples/demo_search/server/plugin.ts b/examples/demo_search/server/plugin.ts index 653aa217717fa..49fbae43e3aa2 100644 --- a/examples/demo_search/server/plugin.ts +++ b/examples/demo_search/server/plugin.ts @@ -20,7 +20,15 @@ import { Plugin, CoreSetup, PluginInitializerContext } from 'kibana/server'; import { PluginSetup as DataPluginSetup } from 'src/plugins/data/server'; import { demoSearchStrategyProvider } from './demo_search_strategy'; -import { DEMO_SEARCH_STRATEGY, IDemoRequest, IDemoResponse } from '../common'; +import { + DEMO_SEARCH_STRATEGY, + IDemoRequest, + IDemoResponse, + ASYNC_DEMO_SEARCH_STRATEGY, + IAsyncDemoRequest, + IAsyncDemoResponse, +} from '../common'; +import { asyncDemoSearchStrategyProvider } from './async_demo_search_strategy'; interface IDemoSearchExplorerDeps { data: DataPluginSetup; @@ -38,10 +46,12 @@ interface IDemoSearchExplorerDeps { declare module '../../../src/plugins/data/server' { export interface IRequestTypesMap { [DEMO_SEARCH_STRATEGY]: IDemoRequest; + [ASYNC_DEMO_SEARCH_STRATEGY]: IAsyncDemoRequest; } export interface IResponseTypesMap { [DEMO_SEARCH_STRATEGY]: IDemoResponse; + [ASYNC_DEMO_SEARCH_STRATEGY]: IAsyncDemoResponse; } } @@ -54,6 +64,11 @@ export class DemoDataPlugin implements Plugin id: 'demoSearch', component: , }, + { + title: 'Async demo search strategy', + id: 'asyncDemoSearch', + component: , + }, ]; const routes = pages.map((page, i) => ( diff --git a/examples/search_explorer/public/async_demo_strategy.tsx b/examples/search_explorer/public/async_demo_strategy.tsx new file mode 100644 index 0000000000000..40ddcc1f48fe7 --- /dev/null +++ b/examples/search_explorer/public/async_demo_strategy.tsx @@ -0,0 +1,123 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { + EuiPageContentBody, + EuiFormRow, + EuiFlexItem, + EuiFlexGroup, + EuiFieldNumber, +} from '@elastic/eui'; +import { ISearchGeneric } from '../../../src/plugins/data/public'; +import { DoSearch } from './do_search'; +import { GuideSection } from './guide_section'; + +import { ASYNC_DEMO_SEARCH_STRATEGY, IAsyncDemoRequest } from '../../demo_search/common'; + +// @ts-ignore +import demoStrategyServerProvider from '!!raw-loader!./../../demo_search/server/async_demo_search_strategy'; +// @ts-ignore +import demoStrategyPublicProvider from '!!raw-loader!./../../demo_search/public/async_demo_search_strategy'; +// @ts-ignore +import demoStrategyServerPlugin from '!!raw-loader!./../../demo_search/server/plugin'; +// @ts-ignore +import demoStrategyPublicPlugin from '!!raw-loader!./../../demo_search/public/plugin'; + +interface Props { + search: ISearchGeneric; +} + +interface State { + searching: boolean; + fibonacciNumbers: number; + changes: boolean; + error?: any; +} + +export class AsyncDemoStrategy extends React.Component { + constructor(props: Props) { + super(props); + + this.state = { + searching: false, + changes: false, + fibonacciNumbers: 5, + }; + } + + renderDemo = () => { + const request: IAsyncDemoRequest = { + fibonacciNumbers: this.state.fibonacciNumbers, + }; + return ( + + + + + this.setState({ fibonacciNumbers: parseFloat(e.target.value) })} + /> + + + + + this.props.search(request, { signal }, ASYNC_DEMO_SEARCH_STRATEGY) + } + /> + + ); + }; + + render() { + return ( + + + + ); + } +} diff --git a/examples/search_explorer/public/do_search.tsx b/examples/search_explorer/public/do_search.tsx index f279b9fcd6e23..a6b6b9b57db4a 100644 --- a/examples/search_explorer/public/do_search.tsx +++ b/examples/search_explorer/public/do_search.tsx @@ -118,8 +118,8 @@ ${requestStr} Response: = ( context: ISearchContext ): ISearchStrategy => { + const syncStrategyProvider = context.getSearchStrategy(SYNC_SEARCH_STRATEGY); + const { search } = syncStrategyProvider(context); return { search: (request, options) => { if (typeof request.params.preference === 'undefined') { @@ -33,11 +35,9 @@ export const esSearchStrategyProvider: TSearchStrategyProvider; + return search({ ...request, serverStrategy: ES_SEARCH_STRATEGY }, options) as Observable< + IEsSearchResponse + >; }, }; }; diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index 762c278a05640..853dbd09e1f93 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -35,7 +35,7 @@ export { export { IEsSearchResponse, IEsSearchRequest, ES_SEARCH_STRATEGY } from '../../common/search'; -export { SYNC_SEARCH_STRATEGY } from './sync_search_strategy'; +export { ISyncSearchRequest, SYNC_SEARCH_STRATEGY } from './sync_search_strategy'; export { IKibanaSearchResponse, IKibanaSearchRequest } from '../../common/search'; diff --git a/src/plugins/data/server/search/create_api.test.ts b/src/plugins/data/server/search/create_api.test.ts index cc13269e1aa21..99e48056ef857 100644 --- a/src/plugins/data/server/search/create_api.test.ts +++ b/src/plugins/data/server/search/create_api.test.ts @@ -25,7 +25,7 @@ import { DEFAULT_SEARCH_STRATEGY } from '../../common/search'; // let mockCoreSetup: MockedKeys; -const mockDefaultSearch = jest.fn(() => Promise.resolve({ percentComplete: 0 })); +const mockDefaultSearch = jest.fn(() => Promise.resolve({ total: 100, loaded: 0 })); const mockDefaultSearchStrategyProvider = jest.fn(() => Promise.resolve({ search: mockDefaultSearch, diff --git a/src/plugins/data/server/search/create_api.ts b/src/plugins/data/server/search/create_api.ts index e1613103ac399..798a4b82caaef 100644 --- a/src/plugins/data/server/search/create_api.ts +++ b/src/plugins/data/server/search/create_api.ts @@ -31,7 +31,7 @@ export function createApi({ }) { const api: IRouteHandlerSearchContext = { search: async (request, options, strategyName) => { - const name = strategyName ? strategyName : DEFAULT_SEARCH_STRATEGY; + const name = strategyName ?? DEFAULT_SEARCH_STRATEGY; const strategyProvider = searchStrategies[name]; if (!strategyProvider) { throw new Error(`No strategy found for ${strategyName}`); @@ -40,6 +40,15 @@ export function createApi({ const strategy = await strategyProvider(caller, api.search); return strategy.search(request, options); }, + cancel: async (id, strategyName) => { + const name = strategyName ?? DEFAULT_SEARCH_STRATEGY; + const strategyProvider = searchStrategies[name]; + if (!strategyProvider) { + throw new Error(`No strategy found for ${strategyName}`); + } + const strategy = await strategyProvider(caller, api.search); + return strategy.cancel && strategy.cancel(id); + }, }; return api; } diff --git a/src/plugins/data/server/search/i_route_handler_search_context.ts b/src/plugins/data/server/search/i_route_handler_search_context.ts index 8a44738a1dcfa..89862781b826e 100644 --- a/src/plugins/data/server/search/i_route_handler_search_context.ts +++ b/src/plugins/data/server/search/i_route_handler_search_context.ts @@ -17,8 +17,9 @@ * under the License. */ -import { ISearchGeneric } from './i_search'; +import { ISearchGeneric, ICancelGeneric } from './i_search'; export interface IRouteHandlerSearchContext { search: ISearchGeneric; + cancel: ICancelGeneric; } diff --git a/src/plugins/data/server/search/i_search.ts b/src/plugins/data/server/search/i_search.ts index 0a35734574153..ea014c5e136d9 100644 --- a/src/plugins/data/server/search/i_search.ts +++ b/src/plugins/data/server/search/i_search.ts @@ -42,7 +42,14 @@ export type ISearchGeneric = Promise; +export type ICancelGeneric = ( + id: string, + strategy?: T +) => Promise; + export type ISearch = ( request: IRequestTypesMap[T], options?: ISearchOptions ) => Promise; + +export type ICancel = (id: string) => Promise; diff --git a/src/plugins/data/server/search/i_search_strategy.ts b/src/plugins/data/server/search/i_search_strategy.ts index d00dd552c9e95..4cfc9608383a9 100644 --- a/src/plugins/data/server/search/i_search_strategy.ts +++ b/src/plugins/data/server/search/i_search_strategy.ts @@ -18,7 +18,7 @@ */ import { APICaller } from 'kibana/server'; -import { ISearch, ISearchGeneric } from './i_search'; +import { ISearch, ICancel, ISearchGeneric } from './i_search'; import { TStrategyTypes } from './strategy_types'; import { ISearchContext } from './i_search_context'; @@ -28,6 +28,7 @@ import { ISearchContext } from './i_search_context'; */ export interface ISearchStrategy { search: ISearch; + cancel?: ICancel; } /** diff --git a/src/plugins/data/server/search/routes.ts b/src/plugins/data/server/search/routes.ts index 11879d14931ae..2b8c4b95ee022 100644 --- a/src/plugins/data/server/search/routes.ts +++ b/src/plugins/data/server/search/routes.ts @@ -35,7 +35,7 @@ export function registerSearchRoute(router: IRouter): void { }, async (context, request, res) => { const searchRequest = request.body; - const strategy = request.params.strategy; + const { strategy } = request.params; const signal = getRequestAbortedSignal(request.events.aborted$); try { @@ -54,4 +54,35 @@ export function registerSearchRoute(router: IRouter): void { } } ); + + router.delete( + { + path: '/internal/search/{strategy}/{id}', + validate: { + params: schema.object({ + strategy: schema.string(), + id: schema.string(), + }), + + query: schema.object({}, { allowUnknowns: true }), + }, + }, + async (context, request, res) => { + const { strategy, id } = request.params; + try { + await context.search!.cancel(id, strategy); + return res.ok(); + } catch (err) { + return res.customError({ + statusCode: err.statusCode, + body: { + message: err.message, + attributes: { + error: err.body.error, + }, + }, + }); + } + } + ); } diff --git a/x-pack/plugins/data_enhanced/public/index.ts b/x-pack/plugins/data_enhanced/public/index.ts index 93b6b7a957182..927716aae9780 100644 --- a/x-pack/plugins/data_enhanced/public/index.ts +++ b/x-pack/plugins/data_enhanced/public/index.ts @@ -9,3 +9,5 @@ import { DataEnhancedPlugin, DataEnhancedSetup, DataEnhancedStart } from './plug export const plugin = () => new DataEnhancedPlugin(); export { DataEnhancedSetup, DataEnhancedStart }; + +export { ASYNC_SEARCH_STRATEGY, IAsyncSearchRequest, IAsyncSearchOptions } from './search'; diff --git a/x-pack/plugins/data_enhanced/public/plugin.ts b/x-pack/plugins/data_enhanced/public/plugin.ts index 14b5382bc85aa..4fe27d400f45f 100644 --- a/x-pack/plugins/data_enhanced/public/plugin.ts +++ b/x-pack/plugins/data_enhanced/public/plugin.ts @@ -8,6 +8,7 @@ import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../../src/plugins/data/public'; import { setAutocompleteService } from './services'; import { setupKqlQuerySuggestionProvider, KUERY_LANGUAGE_NAME } from './autocomplete'; +import { ASYNC_SEARCH_STRATEGY, asyncSearchStrategyProvider } from './search'; export interface DataEnhancedSetupDependencies { data: DataPublicPluginSetup; @@ -20,11 +21,14 @@ export type DataEnhancedSetup = ReturnType; export type DataEnhancedStart = ReturnType; export class DataEnhancedPlugin implements Plugin { - public setup(core: CoreSetup, plugins: DataEnhancedSetupDependencies) { - plugins.data.autocomplete.addQuerySuggestionProvider( + constructor() {} + + public setup(core: CoreSetup, { data }: DataEnhancedSetupDependencies) { + data.autocomplete.addQuerySuggestionProvider( KUERY_LANGUAGE_NAME, setupKqlQuerySuggestionProvider(core) ); + data.search.registerSearchStrategyProvider(ASYNC_SEARCH_STRATEGY, asyncSearchStrategyProvider); } public start(core: CoreStart, plugins: DataEnhancedStartDependencies) { diff --git a/x-pack/plugins/data_enhanced/public/search/async_search_strategy.test.ts b/x-pack/plugins/data_enhanced/public/search/async_search_strategy.test.ts new file mode 100644 index 0000000000000..95f2c9e477064 --- /dev/null +++ b/x-pack/plugins/data_enhanced/public/search/async_search_strategy.test.ts @@ -0,0 +1,125 @@ +/* + * 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 { of } from 'rxjs'; +import { AbortController } from 'abort-controller'; +import { coreMock } from '../../../../../src/core/public/mocks'; +import { asyncSearchStrategyProvider } from './async_search_strategy'; +import { IAsyncSearchOptions } from './types'; +import { CoreStart } from 'kibana/public'; + +describe('Async search strategy', () => { + let mockCoreStart: MockedKeys; + const mockSearch = jest.fn(); + const mockRequest = { params: {}, serverStrategy: 'foo' }; + const mockOptions: IAsyncSearchOptions = { pollInterval: 0 }; + + beforeEach(() => { + mockCoreStart = coreMock.createStart(); + mockSearch.mockReset(); + }); + + it('only sends one request if the first response is complete', async () => { + mockSearch.mockReturnValueOnce(of({ id: 1, total: 1, loaded: 1 })); + + const asyncSearch = asyncSearchStrategyProvider({ + core: mockCoreStart, + getSearchStrategy: jest.fn().mockImplementation(() => { + return () => { + return { + search: mockSearch, + }; + }; + }), + }); + + await asyncSearch.search(mockRequest, mockOptions).toPromise(); + + expect(mockSearch.mock.calls[0][0]).toEqual(mockRequest); + expect(mockSearch.mock.calls[0][1]).toEqual({}); + expect(mockSearch).toBeCalledTimes(1); + }); + + it('stops polling when the response is complete', async () => { + mockSearch + .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 1 })) + .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 2 })) + .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 2 })); + + const asyncSearch = asyncSearchStrategyProvider({ + core: mockCoreStart, + getSearchStrategy: jest.fn().mockImplementation(() => { + return () => { + return { + search: mockSearch, + }; + }; + }), + }); + + expect(mockSearch).toBeCalledTimes(0); + + await asyncSearch.search(mockRequest, mockOptions).toPromise(); + + expect(mockSearch).toBeCalledTimes(2); + }); + + it('only sends the ID and server strategy after the first request', async () => { + mockSearch + .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 1 })) + .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 2 })); + + const asyncSearch = asyncSearchStrategyProvider({ + core: mockCoreStart, + getSearchStrategy: jest.fn().mockImplementation(() => { + return () => { + return { + search: mockSearch, + }; + }; + }), + }); + + expect(mockSearch).toBeCalledTimes(0); + + await asyncSearch.search(mockRequest, mockOptions).toPromise(); + + expect(mockSearch).toBeCalledTimes(2); + expect(mockSearch.mock.calls[0][0]).toEqual(mockRequest); + expect(mockSearch.mock.calls[1][0]).toEqual({ id: 1, serverStrategy: 'foo' }); + }); + + it('sends a DELETE request and stops polling when the signal is aborted', async () => { + mockSearch + .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 1 })) + .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 2 })) + .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 2 })); + + const asyncSearch = asyncSearchStrategyProvider({ + core: mockCoreStart, + getSearchStrategy: jest.fn().mockImplementation(() => { + return () => { + return { + search: mockSearch, + }; + }; + }), + }); + const abortController = new AbortController(); + const options = { ...mockOptions, signal: abortController.signal }; + + const promise = asyncSearch.search(mockRequest, options).toPromise(); + abortController.abort(); + + try { + await promise; + } catch (e) { + expect(e.name).toBe('AbortError'); + expect(mockSearch).toBeCalledTimes(1); + expect(mockCoreStart.http.delete).toBeCalled(); + } + }); +}); diff --git a/x-pack/plugins/data_enhanced/public/search/async_search_strategy.ts b/x-pack/plugins/data_enhanced/public/search/async_search_strategy.ts new file mode 100644 index 0000000000000..fa5d677a53b2a --- /dev/null +++ b/x-pack/plugins/data_enhanced/public/search/async_search_strategy.ts @@ -0,0 +1,75 @@ +/* + * 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 { EMPTY, fromEvent, NEVER, Observable, throwError, timer } from 'rxjs'; +import { mergeMap, expand, takeUntil } from 'rxjs/operators'; +import { + IKibanaSearchResponse, + ISearchContext, + ISearchStrategy, + SYNC_SEARCH_STRATEGY, + TSearchStrategyProvider, +} from '../../../../../src/plugins/data/public'; +import { IAsyncSearchRequest, IAsyncSearchOptions } from './types'; + +export const ASYNC_SEARCH_STRATEGY = 'ASYNC_SEARCH_STRATEGY'; + +declare module '../../../../../src/plugins/data/public' { + export interface IRequestTypesMap { + [ASYNC_SEARCH_STRATEGY]: IAsyncSearchRequest; + } +} + +export const asyncSearchStrategyProvider: TSearchStrategyProvider = ( + context: ISearchContext +): ISearchStrategy => { + const syncStrategyProvider = context.getSearchStrategy(SYNC_SEARCH_STRATEGY); + const { search } = syncStrategyProvider(context); + return { + search: ( + request: IAsyncSearchRequest, + { pollInterval = 1000, ...options }: IAsyncSearchOptions = {} + ): Observable => { + const { serverStrategy } = request; + let id: string | undefined = request.id; + + const aborted$ = options.signal + ? fromEvent(options.signal, 'abort').pipe( + mergeMap(() => { + // If we haven't received the response to the initial request, including the ID, then + // we don't need to send a follow-up request to delete this search. Otherwise, we + // send the follow-up request to delete this search, then throw an abort error. + if (id !== undefined) { + context.core.http.delete(`/internal/search/${request.serverStrategy}/${id}`); + } + + const error = new Error('Aborted'); + error.name = 'AbortError'; + return throwError(error); + }) + ) + : NEVER; + + return search(request, options).pipe( + expand(response => { + // If the response indicates it is complete, stop polling and complete the observable + if ((response.loaded ?? 0) >= (response.total ?? 0)) return EMPTY; + + id = response.id; + + // Delay by the given poll interval + return timer(pollInterval).pipe( + // Send future requests using just the ID from the response + mergeMap(() => { + return search({ id, serverStrategy }, options); + }) + ); + }), + takeUntil(aborted$) + ); + }, + }; +}; diff --git a/x-pack/plugins/data_enhanced/public/search/index.ts b/x-pack/plugins/data_enhanced/public/search/index.ts new file mode 100644 index 0000000000000..a7729aeea5647 --- /dev/null +++ b/x-pack/plugins/data_enhanced/public/search/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { ASYNC_SEARCH_STRATEGY, asyncSearchStrategyProvider } from './async_search_strategy'; +export { IAsyncSearchRequest, IAsyncSearchOptions } from './types'; diff --git a/x-pack/plugins/data_enhanced/public/search/types.ts b/x-pack/plugins/data_enhanced/public/search/types.ts new file mode 100644 index 0000000000000..edaaf1b22654d --- /dev/null +++ b/x-pack/plugins/data_enhanced/public/search/types.ts @@ -0,0 +1,21 @@ +/* + * 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 { ISearchOptions, ISyncSearchRequest } from '../../../../../src/plugins/data/public'; + +export interface IAsyncSearchRequest extends ISyncSearchRequest { + /** + * The ID received from the response from the initial request + */ + id?: string; +} + +export interface IAsyncSearchOptions extends ISearchOptions { + /** + * The number of milliseconds to wait between receiving a response and sending another request + */ + pollInterval?: number; +} From 29439789abc05d05f7a12305397f23469a3499d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?= Date: Tue, 25 Feb 2020 18:18:27 -0500 Subject: [PATCH 076/123] Add migration support to the event log (#58010) * Initial work * Add missing file * Add tests where missing * Add kibana version to esNames * Share ILM policy across versions --- .../server/es/cluster_client_adapter.test.ts | 1 + .../event_log/server/es/cluster_client_adapter.ts | 7 +++++-- .../plugins/event_log/server/es/documents.test.ts | 3 +-- x-pack/plugins/event_log/server/es/documents.ts | 5 +---- x-pack/plugins/event_log/server/es/init.ts | 8 +++++++- x-pack/plugins/event_log/server/es/names.mock.ts | 7 ++++--- x-pack/plugins/event_log/server/es/names.test.ts | 12 +++++++++--- x-pack/plugins/event_log/server/es/names.ts | 14 ++++++++++---- 8 files changed, 38 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts index ecefd4bfa271e..b61196439ee4f 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts @@ -173,6 +173,7 @@ describe('createIndex', () => { await clusterClientAdapter.createIndex('foo'); expect(clusterClient.callAsInternalUser).toHaveBeenCalledWith('indices.create', { index: 'foo', + body: {}, }); }); diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts index c74eeacc9bb19..d585fd4f539b5 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -94,9 +94,12 @@ export class ClusterClientAdapter { return result as boolean; } - public async createIndex(name: string): Promise { + public async createIndex(name: string, body: any = {}): Promise { try { - await this.callEs('indices.create', { index: name }); + await this.callEs('indices.create', { + index: name, + body, + }); } catch (err) { if (err.body?.error?.type !== 'resource_already_exists_exception') { throw new Error(`error creating initial index: ${err.message}`); diff --git a/x-pack/plugins/event_log/server/es/documents.test.ts b/x-pack/plugins/event_log/server/es/documents.test.ts index 7edca4b3943a6..c08d0ac978bc9 100644 --- a/x-pack/plugins/event_log/server/es/documents.test.ts +++ b/x-pack/plugins/event_log/server/es/documents.test.ts @@ -22,8 +22,7 @@ describe('getIndexTemplate()', () => { test('returns the correct details of the index template', () => { const indexTemplate = getIndexTemplate(esNames); - expect(indexTemplate.index_patterns).toEqual([esNames.indexPattern]); - expect(indexTemplate.aliases[esNames.alias]).toEqual({}); + expect(indexTemplate.index_patterns).toEqual([esNames.indexPatternWithVersion]); expect(indexTemplate.settings.number_of_shards).toBeGreaterThanOrEqual(0); expect(indexTemplate.settings.number_of_replicas).toBeGreaterThanOrEqual(0); expect(indexTemplate.settings['index.lifecycle.name']).toBe(esNames.ilmPolicy); diff --git a/x-pack/plugins/event_log/server/es/documents.ts b/x-pack/plugins/event_log/server/es/documents.ts index 09dd7383c4c5e..982454e671008 100644 --- a/x-pack/plugins/event_log/server/es/documents.ts +++ b/x-pack/plugins/event_log/server/es/documents.ts @@ -10,10 +10,7 @@ import mappings from '../../generated/mappings.json'; // returns the body of an index template used in an ES indices.putTemplate call export function getIndexTemplate(esNames: EsNames) { const indexTemplateBody: any = { - index_patterns: [esNames.indexPattern], - aliases: { - [esNames.alias]: {}, - }, + index_patterns: [esNames.indexPatternWithVersion], settings: { number_of_shards: 1, number_of_replicas: 1, diff --git a/x-pack/plugins/event_log/server/es/init.ts b/x-pack/plugins/event_log/server/es/init.ts index 7094277f7aa9f..c67d6541ce002 100644 --- a/x-pack/plugins/event_log/server/es/init.ts +++ b/x-pack/plugins/event_log/server/es/init.ts @@ -62,7 +62,13 @@ class EsInitializationSteps { async createInitialIndexIfNotExists(): Promise { const exists = await this.esContext.esAdapter.doesAliasExist(this.esContext.esNames.alias); if (!exists) { - await this.esContext.esAdapter.createIndex(this.esContext.esNames.initialIndex); + await this.esContext.esAdapter.createIndex(this.esContext.esNames.initialIndex, { + aliases: { + [this.esContext.esNames.alias]: { + is_write_index: true, + }, + }, + }); } } } diff --git a/x-pack/plugins/event_log/server/es/names.mock.ts b/x-pack/plugins/event_log/server/es/names.mock.ts index 7b013a0d263da..268421235b4b2 100644 --- a/x-pack/plugins/event_log/server/es/names.mock.ts +++ b/x-pack/plugins/event_log/server/es/names.mock.ts @@ -9,11 +9,12 @@ import { EsNames } from './names'; const createNamesMock = () => { const mock: jest.Mocked = { base: '.kibana', - alias: '.kibana-event-log', + alias: '.kibana-event-log-8.0.0', ilmPolicy: '.kibana-event-log-policy', indexPattern: '.kibana-event-log-*', - initialIndex: '.kibana-event-log-000001', - indexTemplate: '.kibana-event-log-template', + indexPatternWithVersion: '.kibana-event-log-8.0.0-*', + initialIndex: '.kibana-event-log-8.0.0-000001', + indexTemplate: '.kibana-event-log-8.0.0-template', }; return mock; }; diff --git a/x-pack/plugins/event_log/server/es/names.test.ts b/x-pack/plugins/event_log/server/es/names.test.ts index d88c4212df91c..baefd756bb1ed 100644 --- a/x-pack/plugins/event_log/server/es/names.test.ts +++ b/x-pack/plugins/event_log/server/es/names.test.ts @@ -6,15 +6,21 @@ import { getEsNames } from './names'; +jest.mock('../lib/../../../../package.json', () => ({ + version: '1.2.3', +})); + describe('getEsNames()', () => { test('works as expected', () => { const base = 'XYZ'; + const version = '1.2.3'; const esNames = getEsNames(base); expect(esNames.base).toEqual(base); - expect(esNames.alias).toEqual(`${base}-event-log`); + expect(esNames.alias).toEqual(`${base}-event-log-${version}`); expect(esNames.ilmPolicy).toEqual(`${base}-event-log-policy`); expect(esNames.indexPattern).toEqual(`${base}-event-log-*`); - expect(esNames.initialIndex).toEqual(`${base}-event-log-000001`); - expect(esNames.indexTemplate).toEqual(`${base}-event-log-template`); + expect(esNames.indexPatternWithVersion).toEqual(`${base}-event-log-${version}-*`); + expect(esNames.initialIndex).toEqual(`${base}-event-log-${version}-000001`); + expect(esNames.indexTemplate).toEqual(`${base}-event-log-${version}-template`); }); }); diff --git a/x-pack/plugins/event_log/server/es/names.ts b/x-pack/plugins/event_log/server/es/names.ts index be737d23625f1..d55d02a16fc9a 100644 --- a/x-pack/plugins/event_log/server/es/names.ts +++ b/x-pack/plugins/event_log/server/es/names.ts @@ -4,25 +4,31 @@ * you may not use this file except in compliance with the Elastic License. */ -const EVENT_LOG_NAME_SUFFIX = '-event-log'; +import xPackage from '../../../../package.json'; + +const EVENT_LOG_NAME_SUFFIX = `-event-log`; +const EVENT_LOG_VERSION_SUFFIX = `-${xPackage.version}`; export interface EsNames { base: string; alias: string; ilmPolicy: string; indexPattern: string; + indexPatternWithVersion: string; initialIndex: string; indexTemplate: string; } export function getEsNames(baseName: string): EsNames { const eventLogName = `${baseName}${EVENT_LOG_NAME_SUFFIX}`; + const eventLogNameWithVersion = `${eventLogName}${EVENT_LOG_VERSION_SUFFIX}`; return { base: baseName, - alias: eventLogName, + alias: eventLogNameWithVersion, ilmPolicy: `${eventLogName}-policy`, indexPattern: `${eventLogName}-*`, - initialIndex: `${eventLogName}-000001`, - indexTemplate: `${eventLogName}-template`, + indexPatternWithVersion: `${eventLogNameWithVersion}-*`, + initialIndex: `${eventLogNameWithVersion}-000001`, + indexTemplate: `${eventLogNameWithVersion}-template`, }; } From 24b8ecf74d559ce1226d730ed961d32d5196ef47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?= Date: Tue, 25 Feb 2020 21:47:53 -0500 Subject: [PATCH 077/123] Add localization to missing action types (#58554) --- .../actions/server/builtin_action_types/server_log.ts | 8 ++++---- .../server/builtin_action_types/servicenow.test.ts | 2 +- .../actions/server/builtin_action_types/servicenow.ts | 4 +++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/actions/server/builtin_action_types/server_log.ts b/x-pack/plugins/actions/server/builtin_action_types/server_log.ts index 62406cfaf66e1..01355f2a34f92 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/server_log.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/server_log.ts @@ -12,8 +12,6 @@ import { Logger } from '../../../../../src/core/server'; import { ActionType, ActionTypeExecutorOptions, ActionTypeExecutorResult } from '../types'; import { withoutControlCharacters } from './lib/string_utils'; -const ACTION_NAME = 'Server log'; - // params definition export type ActionParamsType = TypeOf; @@ -37,7 +35,9 @@ const ParamsSchema = schema.object({ export function getActionType({ logger }: { logger: Logger }): ActionType { return { id: '.server-log', - name: ACTION_NAME, + name: i18n.translate('xpack.actions.builtin.serverLogTitle', { + defaultMessage: 'Server log', + }), validate: { params: ParamsSchema, }, @@ -56,7 +56,7 @@ async function executor( const sanitizedMessage = withoutControlCharacters(params.message); try { - logger[params.level](`${ACTION_NAME}: ${sanitizedMessage}`); + logger[params.level](`Server log: ${sanitizedMessage}`); } catch (err) { const message = i18n.translate('xpack.actions.builtin.serverLog.errorLoggingErrorMessage', { defaultMessage: 'error logging message', diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow.test.ts index a6c43f48fa803..9ae96cb23a5c3 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow.test.ts @@ -49,7 +49,7 @@ beforeAll(() => { describe('get()', () => { test('should return correct action type', () => { expect(actionType.id).toEqual(ACTION_TYPE_ID); - expect(actionType.name).toEqual('servicenow'); + expect(actionType.name).toEqual('ServiceNow'); }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow.ts index 2d5c18207def3..0ad435281eba4 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow.ts @@ -89,7 +89,9 @@ export function getActionType({ }): ActionType { return { id: '.servicenow', - name: 'servicenow', + name: i18n.translate('xpack.actions.builtin.servicenowTitle', { + defaultMessage: 'ServiceNow', + }), validate: { config: schema.object(ConfigSchemaProps, { validate: curry(validateConfig)(configurationUtilities), From b56eead4ac7d2ccc5657f51a2be665cbc6118bec Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Tue, 25 Feb 2020 21:59:44 -0500 Subject: [PATCH 078/123] [SIEM] [Detections] Refactor the all rules page (#58428) * Refactor the all rules page to be easier to test * review with Garrett * bring back utility bar under condition * fix bugs tags and allow switch to show loading when enable/disable rule * fix rules selection when trigerring new rules * fix imports/exports can only use rule_id as learned today * review I --- .../detection_engine/rules/use_rules.test.tsx | 99 ++++---- .../detection_engine/rules/use_rules.tsx | 50 ++-- .../detection_engine/rules/use_tags.test.tsx | 8 +- .../detection_engine/rules/use_tags.tsx | 9 +- .../rules/all/__mocks__/mock.ts | 101 -------- .../detection_engine/rules/all/actions.tsx | 51 ++-- .../rules/all/batch_actions.tsx | 74 +++--- .../detection_engine/rules/all/columns.tsx | 92 +++++--- .../rules/all/helpers.test.tsx | 18 +- .../detection_engine/rules/all/helpers.ts | 33 +-- .../detection_engine/rules/all/index.tsx | 220 +++++++++--------- .../detection_engine/rules/all/reducer.ts | 160 ++++++------- .../rules_table_filters.tsx | 6 +- .../__snapshots__/index.test.tsx.snap | 1 + .../rule_actions_overflow/index.tsx | 10 +- .../components/rule_downloader/index.tsx | 14 +- .../pages/detection_engine/rules/index.tsx | 18 +- .../pages/detection_engine/rules/types.ts | 19 -- .../routes/rules/create_rules_bulk_route.ts | 4 +- .../routes/rules/utils.test.ts | 34 ++- .../detection_engine/routes/rules/utils.ts | 15 +- 21 files changed, 461 insertions(+), 575 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_rules.test.tsx b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_rules.test.tsx index b369d3a50730d..242d715e20f77 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_rules.test.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_rules.test.tsx @@ -5,9 +5,8 @@ */ import { renderHook, act } from '@testing-library/react-hooks'; -import { useRules, ReturnRules } from './use_rules'; +import { useRules, UseRules, ReturnRules } from './use_rules'; import * as api from './api'; -import { PaginationOptions, FilterOptions } from '.'; jest.mock('./api'); @@ -17,55 +16,40 @@ describe('useRules', () => { }); test('init', async () => { await act(async () => { - const { result, waitForNextUpdate } = renderHook< - [PaginationOptions, FilterOptions], - ReturnRules - >(props => - useRules( - { + const { result, waitForNextUpdate } = renderHook(props => + useRules({ + pagination: { page: 1, perPage: 10, total: 100, }, - { + filterOptions: { filter: '', sortField: 'created_at', sortOrder: 'desc', - } - ) + }, + }) ); await waitForNextUpdate(); - expect(result.current).toEqual([ - true, - { - data: [], - page: 1, - perPage: 20, - total: 0, - }, - null, - ]); + expect(result.current).toEqual([true, null, result.current[2]]); }); }); test('fetch rules', async () => { await act(async () => { - const { result, waitForNextUpdate } = renderHook< - [PaginationOptions, FilterOptions], - ReturnRules - >(() => - useRules( - { + const { result, waitForNextUpdate } = renderHook(() => + useRules({ + pagination: { page: 1, perPage: 10, total: 100, }, - { + filterOptions: { filter: '', sortField: 'created_at', sortOrder: 'desc', - } - ) + }, + }) ); await waitForNextUpdate(); await waitForNextUpdate(); @@ -148,22 +132,19 @@ describe('useRules', () => { test('re-fetch rules', async () => { const spyOnfetchRules = jest.spyOn(api, 'fetchRules'); await act(async () => { - const { result, waitForNextUpdate } = renderHook< - [PaginationOptions, FilterOptions], - ReturnRules - >(id => - useRules( - { + const { result, waitForNextUpdate } = renderHook(id => + useRules({ + pagination: { page: 1, perPage: 10, total: 100, }, - { + filterOptions: { filter: '', sortField: 'created_at', sortOrder: 'desc', - } - ) + }, + }) ); await waitForNextUpdate(); await waitForNextUpdate(); @@ -178,37 +159,37 @@ describe('useRules', () => { test('fetch rules if props changes', async () => { const spyOnfetchRules = jest.spyOn(api, 'fetchRules'); await act(async () => { - const { rerender, waitForNextUpdate } = renderHook< - [PaginationOptions, FilterOptions], - ReturnRules - >(args => useRules(args[0], args[1]), { - initialProps: [ - { - page: 1, - perPage: 10, - total: 100, - }, - { - filter: '', - sortField: 'created_at', - sortOrder: 'desc', + const { rerender, waitForNextUpdate } = renderHook( + args => useRules(args), + { + initialProps: { + pagination: { + page: 1, + perPage: 10, + total: 100, + }, + filterOptions: { + filter: '', + sortField: 'created_at', + sortOrder: 'desc', + }, }, - ], - }); + } + ); await waitForNextUpdate(); await waitForNextUpdate(); - rerender([ - { + rerender({ + pagination: { page: 1, perPage: 10, total: 100, }, - { + filterOptions: { filter: 'hello world', sortField: 'created_at', sortOrder: 'desc', }, - ]); + }); await waitForNextUpdate(); expect(spyOnfetchRules).toHaveBeenCalledTimes(2); }); diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_rules.tsx b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_rules.tsx index 301a68dc6f445..d05d59d15802d 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_rules.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_rules.tsx @@ -4,16 +4,27 @@ * you may not use this file except in compliance with the Elastic License. */ +import { noop } from 'lodash/fp'; import { useEffect, useState, useRef } from 'react'; -import { FetchRulesResponse, FilterOptions, PaginationOptions } from './types'; +import { FetchRulesResponse, FilterOptions, PaginationOptions, Rule } from './types'; import { useStateToaster } from '../../../components/toasters'; import { fetchRules } from './api'; import { errorToToaster } from '../../../components/ml/api/error_to_toaster'; import * as i18n from './translations'; -type Func = () => void; -export type ReturnRules = [boolean, FetchRulesResponse, Func | null]; +export type ReturnRules = [ + boolean, + FetchRulesResponse | null, + (refreshPrePackagedRule?: boolean) => void +]; + +export interface UseRules { + pagination: PaginationOptions; + filterOptions: FilterOptions; + refetchPrePackagedRulesStatus?: () => void; + dispatchRulesInReducer?: (rules: Rule[]) => void; +} /** * Hook for using the list of Rules from the Detection Engine API @@ -21,17 +32,14 @@ export type ReturnRules = [boolean, FetchRulesResponse, Func | null]; * @param pagination desired pagination options (e.g. page/perPage) * @param filterOptions desired filters (e.g. filter/sortField/sortOrder) */ -export const useRules = ( - pagination: PaginationOptions, - filterOptions: FilterOptions -): ReturnRules => { - const [rules, setRules] = useState({ - page: 1, - perPage: 20, - total: 0, - data: [], - }); - const reFetchRules = useRef(null); +export const useRules = ({ + pagination, + filterOptions, + refetchPrePackagedRulesStatus, + dispatchRulesInReducer, +}: UseRules): ReturnRules => { + const [rules, setRules] = useState(null); + const reFetchRules = useRef<(refreshPrePackagedRule?: boolean) => void>(noop); const [loading, setLoading] = useState(true); const [, dispatchToaster] = useStateToaster(); @@ -50,10 +58,16 @@ export const useRules = ( if (isSubscribed) { setRules(fetchRulesResult); + if (dispatchRulesInReducer != null) { + dispatchRulesInReducer(fetchRulesResult.data); + } } } catch (error) { if (isSubscribed) { errorToToaster({ title: i18n.RULE_FETCH_FAILURE, error, dispatchToaster }); + if (dispatchRulesInReducer != null) { + dispatchRulesInReducer([]); + } } } if (isSubscribed) { @@ -62,7 +76,12 @@ export const useRules = ( } fetchData(); - reFetchRules.current = fetchData.bind(null, true); + reFetchRules.current = (refreshPrePackagedRule: boolean = false) => { + fetchData(true); + if (refreshPrePackagedRule && refetchPrePackagedRulesStatus != null) { + refetchPrePackagedRulesStatus(); + } + }; return () => { isSubscribed = false; abortCtrl.abort(); @@ -76,6 +95,7 @@ export const useRules = ( filterOptions.tags?.sort().join(), filterOptions.showCustomRules, filterOptions.showElasticRules, + refetchPrePackagedRulesStatus, ]); return [loading, rules, reFetchRules.current]; diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_tags.test.tsx b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_tags.test.tsx index 4a796efa5b0cb..68f54b35754f6 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_tags.test.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_tags.test.tsx @@ -14,7 +14,7 @@ describe('useTags', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook(() => useTags()); await waitForNextUpdate(); - expect(result.current).toEqual([true, []]); + expect(result.current).toEqual([true, [], result.current[2]]); }); }); @@ -23,7 +23,11 @@ describe('useTags', () => { const { result, waitForNextUpdate } = renderHook(() => useTags()); await waitForNextUpdate(); await waitForNextUpdate(); - expect(result.current).toEqual([false, ['elastic', 'love', 'quality', 'code']]); + expect(result.current).toEqual([ + false, + ['elastic', 'love', 'quality', 'code'], + result.current[2], + ]); }); }); }); diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_tags.tsx b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_tags.tsx index 196d4b1420561..5985200fa16ec 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_tags.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_tags.tsx @@ -4,13 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { useEffect, useState } from 'react'; +import { noop } from 'lodash/fp'; +import { useEffect, useState, useRef } from 'react'; import { useStateToaster } from '../../../components/toasters'; import { fetchTags } from './api'; import { errorToToaster } from '../../../components/ml/api/error_to_toaster'; import * as i18n from './translations'; -export type ReturnTags = [boolean, string[]]; +export type ReturnTags = [boolean, string[], () => void]; /** * Hook for using the list of Tags from the Detection Engine API @@ -20,6 +21,7 @@ export const useTags = (): ReturnTags => { const [tags, setTags] = useState([]); const [loading, setLoading] = useState(true); const [, dispatchToaster] = useStateToaster(); + const reFetchTags = useRef<() => void>(noop); useEffect(() => { let isSubscribed = true; @@ -46,6 +48,7 @@ export const useTags = (): ReturnTags => { } fetchData(); + reFetchTags.current = fetchData; return () => { isSubscribed = false; @@ -53,5 +56,5 @@ export const useTags = (): ReturnTags => { }; }, []); - return [loading, tags]; + return [loading, tags, reFetchTags.current]; }; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/__mocks__/mock.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/__mocks__/mock.ts index 980575f1470a5..e2287e5eeeb3f 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/__mocks__/mock.ts +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/__mocks__/mock.ts @@ -5,7 +5,6 @@ */ import { Rule, RuleError } from '../../../../../containers/detection_engine/rules'; -import { TableData } from '../../types'; export const mockRule = (id: string): Rule => ({ created_at: '2020-01-10T21:11:45.839Z', @@ -50,103 +49,3 @@ export const mockRules: Rule[] = [ mockRule('abe6c564-050d-45a5-aaf0-386c37dd1f61'), mockRule('63f06f34-c181-4b2d-af35-f2ace572a1ee'), ]; -export const mockTableData: TableData[] = [ - { - activate: true, - id: 'abe6c564-050d-45a5-aaf0-386c37dd1f61', - immutable: false, - isLoading: false, - risk_score: 21, - rule: { - href: '#/detections/rules/id/abe6c564-050d-45a5-aaf0-386c37dd1f61', - name: 'Home Grown!', - }, - rule_id: 'b5ba41ab-aaf3-4f43-971b-bdf9434ce0ea', - severity: 'low', - sourceRule: { - created_at: '2020-01-10T21:11:45.839Z', - created_by: 'elastic', - description: '24/7', - enabled: true, - false_positives: [], - filters: [], - from: 'now-300s', - id: 'abe6c564-050d-45a5-aaf0-386c37dd1f61', - immutable: false, - index: ['auditbeat-*'], - interval: '5m', - language: 'kuery', - max_signals: 100, - meta: { from: '0m' }, - name: 'Home Grown!', - output_index: '.siem-signals-default', - query: '', - references: [], - risk_score: 21, - rule_id: 'b5ba41ab-aaf3-4f43-971b-bdf9434ce0ea', - saved_id: "Garrett's IP", - severity: 'low', - tags: [], - threat: [], - timeline_id: '86aa74d0-2136-11ea-9864-ebc8cc1cb8c2', - timeline_title: 'Untitled timeline', - to: 'now', - type: 'saved_query', - updated_at: '2020-01-10T21:11:45.839Z', - updated_by: 'elastic', - version: 1, - }, - status: null, - statusDate: null, - tags: [], - }, - { - activate: true, - id: '63f06f34-c181-4b2d-af35-f2ace572a1ee', - immutable: false, - isLoading: false, - risk_score: 21, - rule: { - href: '#/detections/rules/id/63f06f34-c181-4b2d-af35-f2ace572a1ee', - name: 'Home Grown!', - }, - rule_id: 'b5ba41ab-aaf3-4f43-971b-bdf9434ce0ea', - severity: 'low', - sourceRule: { - created_at: '2020-01-10T21:11:45.839Z', - created_by: 'elastic', - description: '24/7', - enabled: true, - false_positives: [], - filters: [], - from: 'now-300s', - id: '63f06f34-c181-4b2d-af35-f2ace572a1ee', - immutable: false, - index: ['auditbeat-*'], - interval: '5m', - language: 'kuery', - max_signals: 100, - meta: { from: '0m' }, - name: 'Home Grown!', - output_index: '.siem-signals-default', - query: '', - references: [], - risk_score: 21, - rule_id: 'b5ba41ab-aaf3-4f43-971b-bdf9434ce0ea', - saved_id: "Garrett's IP", - severity: 'low', - tags: [], - threat: [], - timeline_id: '86aa74d0-2136-11ea-9864-ebc8cc1cb8c2', - timeline_title: 'Untitled timeline', - to: 'now', - type: 'saved_query', - updated_at: '2020-01-10T21:11:45.839Z', - updated_by: 'elastic', - version: 1, - }, - status: null, - statusDate: null, - tags: [], - }, -]; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/actions.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/actions.tsx index 6212c2067384d..a17fd34d1c344 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/actions.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/actions.tsx @@ -32,53 +32,58 @@ export const editRuleAction = (rule: Rule, history: H.History) => { export const duplicateRulesAction = async ( rules: Rule[], + ruleIds: string[], dispatch: React.Dispatch, dispatchToaster: Dispatch ) => { try { - const ruleIds = rules.map(r => r.id); - dispatch({ type: 'updateLoading', ids: ruleIds, isLoading: true }); - const duplicatedRules = await duplicateRules({ rules }); - dispatch({ type: 'refresh' }); - displaySuccessToast( - i18n.SUCCESSFULLY_DUPLICATED_RULES(duplicatedRules.length), - dispatchToaster - ); + dispatch({ type: 'loadingRuleIds', ids: ruleIds, actionType: 'duplicate' }); + const response = await duplicateRules({ rules }); + const { errors } = bucketRulesResponse(response); + if (errors.length > 0) { + displayErrorToast( + i18n.DUPLICATE_RULE_ERROR, + errors.map(e => e.error.message), + dispatchToaster + ); + } else { + displaySuccessToast(i18n.SUCCESSFULLY_DUPLICATED_RULES(ruleIds.length), dispatchToaster); + } + dispatch({ type: 'loadingRuleIds', ids: [], actionType: null }); } catch (e) { + dispatch({ type: 'loadingRuleIds', ids: [], actionType: null }); displayErrorToast(i18n.DUPLICATE_RULE_ERROR, [e.message], dispatchToaster); } }; -export const exportRulesAction = async (rules: Rule[], dispatch: React.Dispatch) => { - dispatch({ type: 'setExportPayload', exportPayload: rules }); +export const exportRulesAction = (exportRuleId: string[], dispatch: React.Dispatch) => { + dispatch({ type: 'exportRuleIds', ids: exportRuleId }); }; export const deleteRulesAction = async ( - ids: string[], + ruleIds: string[], dispatch: React.Dispatch, dispatchToaster: Dispatch, onRuleDeleted?: () => void ) => { try { - dispatch({ type: 'loading', isLoading: true }); - - const response = await deleteRules({ ids }); + dispatch({ type: 'loadingRuleIds', ids: ruleIds, actionType: 'delete' }); + const response = await deleteRules({ ids: ruleIds }); const { errors } = bucketRulesResponse(response); - - dispatch({ type: 'refresh' }); + dispatch({ type: 'loadingRuleIds', ids: [], actionType: null }); if (errors.length > 0) { displayErrorToast( - i18n.BATCH_ACTION_DELETE_SELECTED_ERROR(ids.length), + i18n.BATCH_ACTION_DELETE_SELECTED_ERROR(ruleIds.length), errors.map(e => e.error.message), dispatchToaster ); - } else { - // FP: See https://github.com/typescript-eslint/typescript-eslint/issues/1138#issuecomment-566929566 - onRuleDeleted?.(); // eslint-disable-line no-unused-expressions + } else if (onRuleDeleted) { + onRuleDeleted(); } } catch (e) { + dispatch({ type: 'loadingRuleIds', ids: [], actionType: null }); displayErrorToast( - i18n.BATCH_ACTION_DELETE_SELECTED_ERROR(ids.length), + i18n.BATCH_ACTION_DELETE_SELECTED_ERROR(ruleIds.length), [e.message], dispatchToaster ); @@ -96,7 +101,7 @@ export const enableRulesAction = async ( : i18n.BATCH_ACTION_DEACTIVATE_SELECTED_ERROR(ids.length); try { - dispatch({ type: 'updateLoading', ids, isLoading: true }); + dispatch({ type: 'loadingRuleIds', ids, actionType: enabled ? 'enable' : 'disable' }); const response = await enableRules({ ids, enabled }); const { rules, errors } = bucketRulesResponse(response); @@ -125,6 +130,6 @@ export const enableRulesAction = async ( } } catch (e) { displayErrorToast(errorTitle, [e.message], dispatchToaster); - dispatch({ type: 'updateLoading', ids, isLoading: false }); + dispatch({ type: 'loadingRuleIds', ids: [], actionType: null }); } }; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/batch_actions.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/batch_actions.tsx index 8a10d4f7100b9..a0942d7f6534a 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/batch_actions.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/batch_actions.tsx @@ -6,9 +6,7 @@ import { EuiContextMenuItem } from '@elastic/eui'; import React, { Dispatch } from 'react'; -import * as H from 'history'; import * as i18n from '../translations'; -import { TableData } from '../types'; import { Action } from './reducer'; import { deleteRulesAction, @@ -17,18 +15,37 @@ import { exportRulesAction, } from './actions'; import { ActionToaster } from '../../../../components/toasters'; +import { Rule } from '../../../../containers/detection_engine/rules'; -export const getBatchItems = ( - selectedState: TableData[], - dispatch: Dispatch, - dispatchToaster: Dispatch, - history: H.History, - closePopover: () => void -) => { - const containsEnabled = selectedState.some(v => v.activate); - const containsDisabled = selectedState.some(v => !v.activate); - const containsLoading = selectedState.some(v => v.isLoading); - const containsImmutable = selectedState.some(v => v.immutable); +interface GetBatchItems { + closePopover: () => void; + dispatch: Dispatch; + dispatchToaster: Dispatch; + loadingRuleIds: string[]; + reFetchRules: (refreshPrePackagedRule?: boolean) => void; + rules: Rule[]; + selectedRuleIds: string[]; +} + +export const getBatchItems = ({ + closePopover, + dispatch, + dispatchToaster, + loadingRuleIds, + reFetchRules, + rules, + selectedRuleIds, +}: GetBatchItems) => { + const containsEnabled = selectedRuleIds.some( + id => rules.find(r => r.id === id)?.enabled ?? false + ); + const containsDisabled = selectedRuleIds.some( + id => !rules.find(r => r.id === id)?.enabled ?? false + ); + const containsLoading = selectedRuleIds.some(id => loadingRuleIds.includes(id)); + const containsImmutable = selectedRuleIds.some( + id => rules.find(r => r.id === id)?.immutable ?? false + ); return [ { closePopover(); - const deactivatedIds = selectedState.filter(s => !s.activate).map(s => s.id); + const deactivatedIds = selectedRuleIds.filter( + id => !rules.find(r => r.id === id)?.enabled ?? false + ); await enableRulesAction(deactivatedIds, true, dispatch, dispatchToaster); }} > @@ -49,7 +68,9 @@ export const getBatchItems = ( disabled={containsLoading || !containsEnabled} onClick={async () => { closePopover(); - const activatedIds = selectedState.filter(s => s.activate).map(s => s.id); + const activatedIds = selectedRuleIds.filter( + id => rules.find(r => r.id === id)?.enabled ?? false + ); await enableRulesAction(activatedIds, false, dispatch, dispatchToaster); }} > @@ -58,11 +79,11 @@ export const getBatchItems = ( { + disabled={containsImmutable || containsLoading || selectedRuleIds.length === 0} + onClick={() => { closePopover(); - await exportRulesAction( - selectedState.map(s => s.sourceRule), + exportRulesAction( + rules.filter(r => selectedRuleIds.includes(r.id)).map(r => r.rule_id), dispatch ); }} @@ -72,14 +93,16 @@ export const getBatchItems = ( { closePopover(); await duplicateRulesAction( - selectedState.map(s => s.sourceRule), + rules.filter(r => selectedRuleIds.includes(r.id)), + selectedRuleIds, dispatch, dispatchToaster ); + reFetchRules(true); }} > {i18n.BATCH_ACTION_DUPLICATE_SELECTED} @@ -88,14 +111,11 @@ export const getBatchItems = ( key={i18n.BATCH_ACTION_DELETE_SELECTED} icon="trash" title={containsImmutable ? i18n.BATCH_ACTION_DELETE_SELECTED_IMMUTABLE : undefined} - disabled={containsLoading || selectedState.length === 0} + disabled={containsLoading || selectedRuleIds.length === 0} onClick={async () => { closePopover(); - await deleteRulesAction( - selectedState.map(({ sourceRule: { id } }) => id), - dispatch, - dispatchToaster - ); + await deleteRulesAction(selectedRuleIds, dispatch, dispatchToaster); + reFetchRules(true); }} > {i18n.BATCH_ACTION_DELETE_SELECTED} diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/columns.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/columns.tsx index d648854368c28..ff104f09d68ef 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/columns.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/columns.tsx @@ -15,72 +15,92 @@ import { } from '@elastic/eui'; import * as H from 'history'; import React, { Dispatch } from 'react'; + +import { Rule } from '../../../../containers/detection_engine/rules'; import { getEmptyTagValue } from '../../../../components/empty_value'; +import { FormattedDate } from '../../../../components/formatted_date'; +import { getRuleDetailsUrl } from '../../../../components/link_to/redirect_to_detection_engine'; +import { ActionToaster } from '../../../../components/toasters'; +import { TruncatableText } from '../../../../components/truncatable_text'; +import { getStatusColor } from '../components/rule_status/helpers'; +import { RuleSwitch } from '../components/rule_switch'; +import { SeverityBadge } from '../components/severity_badge'; +import * as i18n from '../translations'; import { deleteRulesAction, duplicateRulesAction, editRuleAction, exportRulesAction, } from './actions'; - import { Action } from './reducer'; -import { TableData } from '../types'; -import * as i18n from '../translations'; -import { FormattedDate } from '../../../../components/formatted_date'; -import { RuleSwitch } from '../components/rule_switch'; -import { SeverityBadge } from '../components/severity_badge'; -import { ActionToaster } from '../../../../components/toasters'; -import { getStatusColor } from '../components/rule_status/helpers'; -import { TruncatableText } from '../../../../components/truncatable_text'; const getActions = ( dispatch: React.Dispatch, dispatchToaster: Dispatch, - history: H.History + history: H.History, + reFetchRules: (refreshPrePackagedRule?: boolean) => void ) => [ { description: i18n.EDIT_RULE_SETTINGS, icon: 'visControls', name: i18n.EDIT_RULE_SETTINGS, - onClick: (rowItem: TableData) => editRuleAction(rowItem.sourceRule, history), - enabled: (rowItem: TableData) => !rowItem.sourceRule.immutable, + onClick: (rowItem: Rule) => editRuleAction(rowItem, history), + enabled: (rowItem: Rule) => !rowItem.immutable, }, { description: i18n.DUPLICATE_RULE, icon: 'copy', name: i18n.DUPLICATE_RULE, - onClick: (rowItem: TableData) => - duplicateRulesAction([rowItem.sourceRule], dispatch, dispatchToaster), + onClick: (rowItem: Rule) => { + duplicateRulesAction([rowItem], [rowItem.id], dispatch, dispatchToaster); + reFetchRules(true); + }, }, { description: i18n.EXPORT_RULE, icon: 'exportAction', name: i18n.EXPORT_RULE, - onClick: (rowItem: TableData) => exportRulesAction([rowItem.sourceRule], dispatch), - enabled: (rowItem: TableData) => !rowItem.immutable, + onClick: (rowItem: Rule) => exportRulesAction([rowItem.rule_id], dispatch), + enabled: (rowItem: Rule) => !rowItem.immutable, }, { description: i18n.DELETE_RULE, icon: 'trash', name: i18n.DELETE_RULE, - onClick: (rowItem: TableData) => deleteRulesAction([rowItem.id], dispatch, dispatchToaster), + onClick: (rowItem: Rule) => { + deleteRulesAction([rowItem.id], dispatch, dispatchToaster); + reFetchRules(true); + }, }, ]; -type RulesColumns = EuiBasicTableColumn | EuiTableActionsColumnType; +type RulesColumns = EuiBasicTableColumn | EuiTableActionsColumnType; + +interface GetColumns { + dispatch: React.Dispatch; + dispatchToaster: Dispatch; + history: H.History; + hasNoPermissions: boolean; + loadingRuleIds: string[]; + reFetchRules: (refreshPrePackagedRule?: boolean) => void; +} // Michael: Are we able to do custom, in-table-header filters, as shown in my wireframes? -export const getColumns = ( - dispatch: React.Dispatch, - dispatchToaster: Dispatch, - history: H.History, - hasNoPermissions: boolean -): RulesColumns[] => { +export const getColumns = ({ + dispatch, + dispatchToaster, + history, + hasNoPermissions, + loadingRuleIds, + reFetchRules, +}: GetColumns): RulesColumns[] => { const cols: RulesColumns[] = [ { - field: 'rule', + field: 'name', name: i18n.COLUMN_RULE, - render: (value: TableData['rule']) => {value.name}, + render: (value: Rule['name'], item: Rule) => ( + {value} + ), truncateText: true, width: '24%', }, @@ -93,14 +113,14 @@ export const getColumns = ( { field: 'severity', name: i18n.COLUMN_SEVERITY, - render: (value: TableData['severity']) => , + render: (value: Rule['severity']) => , truncateText: true, width: '16%', }, { - field: 'statusDate', + field: 'status_date', name: i18n.COLUMN_LAST_COMPLETE_RUN, - render: (value: TableData['statusDate']) => { + render: (value: Rule['status_date']) => { return value == null ? ( getEmptyTagValue() ) : ( @@ -114,7 +134,7 @@ export const getColumns = ( { field: 'status', name: i18n.COLUMN_LAST_RESPONSE, - render: (value: TableData['status']) => { + render: (value: Rule['status']) => { return ( <> @@ -129,7 +149,7 @@ export const getColumns = ( { field: 'tags', name: i18n.COLUMN_TAGS, - render: (value: TableData['tags']) => ( + render: (value: Rule['tags']) => ( {value.map((tag, i) => ( @@ -145,13 +165,13 @@ export const getColumns = ( align: 'center', field: 'activate', name: i18n.COLUMN_ACTIVATE, - render: (value: TableData['activate'], item: TableData) => ( + render: (value: Rule['enabled'], item: Rule) => ( ), sortable: true, @@ -160,9 +180,9 @@ export const getColumns = ( ]; const actions: RulesColumns[] = [ { - actions: getActions(dispatch, dispatchToaster, history), + actions: getActions(dispatch, dispatchToaster, history, reFetchRules), width: '40px', - } as EuiTableActionsColumnType, + } as EuiTableActionsColumnType, ]; return hasNoPermissions ? cols : [...cols, ...actions]; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/helpers.test.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/helpers.test.tsx index e925161444e42..c60933733587d 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/helpers.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/helpers.test.tsx @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { bucketRulesResponse, formatRules } from './helpers'; -import { mockRule, mockRuleError, mockRules, mockTableData } from './__mocks__/mock'; +import { bucketRulesResponse } from './helpers'; +import { mockRule, mockRuleError } from './__mocks__/mock'; import uuid from 'uuid'; import { Rule, RuleError } from '../../../../containers/detection_engine/rules'; @@ -15,20 +15,6 @@ describe('AllRulesTable Helpers', () => { const mockRuleError1: Readonly = mockRuleError(uuid.v4()); const mockRuleError2: Readonly = mockRuleError(uuid.v4()); - describe('formatRules', () => { - test('formats rules with no selection', () => { - const formattedRules = formatRules(mockRules); - expect(formattedRules).toEqual(mockTableData); - }); - - test('formats rules with selection', () => { - const mockTableDataWithSelected = [...mockTableData]; - mockTableDataWithSelected[0].isLoading = true; - const formattedRules = formatRules(mockRules, [mockRules[0].id]); - expect(formattedRules).toEqual(mockTableDataWithSelected); - }); - }); - describe('bucketRulesResponse', () => { test('buckets empty response', () => { const bucketedResponse = bucketRulesResponse([]); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/helpers.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/helpers.ts index 9a523536694d9..5ce26144a4d9c 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/helpers.ts +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/helpers.ts @@ -9,32 +9,6 @@ import { RuleError, RuleResponseBuckets, } from '../../../../containers/detection_engine/rules'; -import { TableData } from '../types'; - -/** - * Formats rules into the correct format for the AllRulesTable - * - * @param rules as returned from the Rules API - * @param selectedIds ids of the currently selected rules - */ -export const formatRules = (rules: Rule[], selectedIds?: string[]): TableData[] => - rules.map(rule => ({ - id: rule.id, - immutable: rule.immutable, - rule_id: rule.rule_id, - rule: { - href: `#/detections/rules/id/${encodeURIComponent(rule.id)}`, - name: rule.name, - }, - risk_score: rule.risk_score, - severity: rule.severity, - tags: rule.tags ?? [], - activate: rule.enabled, - status: rule.status ?? null, - statusDate: rule.status_date ?? null, - sourceRule: rule, - isLoading: selectedIds?.includes(rule.id) ?? false, - })); /** * Separates rules/errors from bulk rules API response (create/update/delete) @@ -52,14 +26,11 @@ export const bucketRulesResponse = (response: Array) => ); export const showRulesTable = ({ - isInitialLoad, rulesCustomInstalled, rulesInstalled, }: { - isInitialLoad: boolean; rulesCustomInstalled: number | null; rulesInstalled: number | null; }) => - !isInitialLoad && - ((rulesCustomInstalled != null && rulesCustomInstalled > 0) || - (rulesInstalled != null && rulesInstalled > 0)); + (rulesCustomInstalled != null && rulesCustomInstalled > 0) || + (rulesInstalled != null && rulesInstalled > 0); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/index.tsx index b304d77f2e276..79fec526faf48 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/index.tsx @@ -11,15 +11,16 @@ import { EuiLoadingContent, EuiSpacer, } from '@elastic/eui'; -import { isEmpty } from 'lodash/fp'; -import React, { useCallback, useEffect, useMemo, useReducer, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react'; import { useHistory } from 'react-router-dom'; +import styled from 'styled-components'; import uuid from 'uuid'; import { useRules, CreatePreBuiltRules, FilterOptions, + Rule, } from '../../../../containers/detection_engine/rules'; import { HeaderSection } from '../../../../components/header_section'; import { @@ -36,35 +37,39 @@ import { PrePackagedRulesPrompt } from '../components/pre_packaged_rules/load_em import { RuleDownloader } from '../components/rule_downloader'; import { getPrePackagedRuleStatus } from '../helpers'; import * as i18n from '../translations'; -import { EuiBasicTableOnChange, TableData } from '../types'; +import { EuiBasicTableOnChange } from '../types'; import { getBatchItems } from './batch_actions'; import { getColumns } from './columns'; import { showRulesTable } from './helpers'; import { allRulesReducer, State } from './reducer'; import { RulesTableFilters } from './rules_table_filters/rules_table_filters'; +// EuiBasicTable give me a hardtime with adding the ref attributes so I went the easy way +// after few hours of fight with typescript !!!! I lost :( +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const MyEuiBasicTable = styled(EuiBasicTable as any)`` as any; + const initialState: State = { - isLoading: true, - rules: [], - tableData: [], - selectedItems: [], - refreshToggle: true, - pagination: { - page: 1, - perPage: 20, - total: 0, - }, + exportRuleIds: [], filterOptions: { filter: '', sortField: 'enabled', sortOrder: 'desc', }, + loadingRuleIds: [], + loadingRulesAction: null, + pagination: { + page: 1, + perPage: 20, + total: 0, + }, + rules: [], + selectedRuleIds: [], }; interface AllRulesProps { createPrePackagedRules: CreatePreBuiltRules | null; hasNoPermissions: boolean; - importCompleteToggle: boolean; loading: boolean; loadingCreatePrePackagedRules: boolean; refetchPrePackagedRulesStatus: () => void; @@ -72,7 +77,7 @@ interface AllRulesProps { rulesInstalled: number | null; rulesNotInstalled: number | null; rulesNotUpdated: number | null; - setRefreshRulesData: (refreshRule: () => void) => void; + setRefreshRulesData: (refreshRule: (refreshPrePackagedRule?: boolean) => void) => void; } /** @@ -87,7 +92,6 @@ export const AllRules = React.memo( ({ createPrePackagedRules, hasNoPermissions, - importCompleteToggle, loading, loadingCreatePrePackagedRules, refetchPrePackagedRulesStatus, @@ -97,24 +101,36 @@ export const AllRules = React.memo( rulesNotUpdated, setRefreshRulesData, }) => { + const [initLoading, setInitLoading] = useState(true); + const tableRef = useRef(); const [ { - exportPayload, + exportRuleIds, filterOptions, - isLoading, - refreshToggle, - selectedItems, - tableData, + loadingRuleIds, + loadingRulesAction, pagination, + rules, + selectedRuleIds, }, dispatch, - ] = useReducer(allRulesReducer, initialState); + ] = useReducer(allRulesReducer(tableRef), initialState); const history = useHistory(); - const [oldRefreshToggle, setOldRefreshToggle] = useState(refreshToggle); - const [isInitialLoad, setIsInitialLoad] = useState(true); - const [isGlobalLoading, setIsGlobalLoad] = useState(false); const [, dispatchToaster] = useStateToaster(); - const [isLoadingRules, rulesData, reFetchRulesData] = useRules(pagination, filterOptions); + + const setRules = useCallback((newRules: Rule[]) => { + dispatch({ + type: 'setRules', + rules: newRules, + }); + }, []); + + const [isLoadingRules, , reFetchRulesData] = useRules({ + pagination, + filterOptions, + refetchPrePackagedRulesStatus, + dispatchRulesInReducer: setRules, + }); const prePackagedRuleStatus = getPrePackagedRuleStatus( rulesInstalled, @@ -125,10 +141,18 @@ export const AllRules = React.memo( const getBatchItemsPopoverContent = useCallback( (closePopover: () => void) => ( ), - [selectedItems, dispatch, dispatchToaster, history] + [dispatch, dispatchToaster, loadingRuleIds, reFetchRulesData, rules, selectedRuleIds] ); const tableOnChangeCallback = useCallback( @@ -146,46 +170,19 @@ export const AllRules = React.memo( ); const columns = useMemo(() => { - return getColumns(dispatch, dispatchToaster, history, hasNoPermissions); - }, [dispatch, dispatchToaster, history]); - - useEffect(() => { - dispatch({ type: 'loading', isLoading: isLoadingRules }); - }, [isLoadingRules]); - - useEffect(() => { - if (!isLoadingRules && !loading && isInitialLoad) { - setIsInitialLoad(false); - } - }, [isInitialLoad, isLoadingRules, loading]); - - useEffect(() => { - if (!isGlobalLoading && (isLoadingRules || isLoading)) { - setIsGlobalLoad(true); - } else if (isGlobalLoading && !isLoadingRules && !isLoading) { - setIsGlobalLoad(false); - } - }, [setIsGlobalLoad, isGlobalLoading, isLoadingRules, isLoading]); - - useEffect(() => { - if (!isInitialLoad) { - dispatch({ type: 'refresh' }); - } - }, [importCompleteToggle]); - - useEffect(() => { - if (!isInitialLoad && reFetchRulesData != null && oldRefreshToggle !== refreshToggle) { - setOldRefreshToggle(refreshToggle); - reFetchRulesData(); - refetchPrePackagedRulesStatus(); - } - }, [ - isInitialLoad, - refreshToggle, - oldRefreshToggle, - reFetchRulesData, - refetchPrePackagedRulesStatus, - ]); + return getColumns({ + dispatch, + dispatchToaster, + history, + hasNoPermissions, + loadingRuleIds: + loadingRulesAction != null && + (loadingRulesAction === 'enable' || loadingRulesAction === 'disable') + ? loadingRuleIds + : [], + reFetchRules: reFetchRulesData, + }); + }, [dispatch, dispatchToaster, history, loadingRuleIds, loadingRulesAction, reFetchRulesData]); useEffect(() => { if (reFetchRulesData != null) { @@ -194,31 +191,25 @@ export const AllRules = React.memo( }, [reFetchRulesData, setRefreshRulesData]); useEffect(() => { - dispatch({ - type: 'updateRules', - rules: rulesData.data, - pagination: { - page: rulesData.page, - perPage: rulesData.perPage, - total: rulesData.total, - }, - }); - }, [rulesData]); + if (initLoading && !loading && !isLoadingRules) { + setInitLoading(false); + } + }, [initLoading, loading, isLoadingRules]); const handleCreatePrePackagedRules = useCallback(async () => { - if (createPrePackagedRules != null) { + if (createPrePackagedRules != null && reFetchRulesData != null) { await createPrePackagedRules(); - dispatch({ type: 'refresh' }); + reFetchRulesData(true); } - }, [createPrePackagedRules]); + }, [createPrePackagedRules, reFetchRulesData]); const euiBasicTableSelectionProps = useMemo( () => ({ - selectable: (item: TableData) => !item.isLoading, - onSelectionChange: (selected: TableData[]) => - dispatch({ type: 'setSelected', selectedItems: selected }), + selectable: (item: Rule) => !loadingRuleIds.includes(item.id), + onSelectionChange: (selected: Rule[]) => + dispatch({ type: 'selectedRuleIds', ids: selected.map(r => r.id) }), }), - [] + [loadingRuleIds] ); const onFilterChangedCallback = useCallback((newFilterOptions: Partial) => { @@ -237,12 +228,25 @@ export const AllRules = React.memo( ); }, []); + const isLoadingAnActionOnRule = useMemo(() => { + if ( + loadingRuleIds.length > 0 && + (loadingRulesAction === 'disable' || loadingRulesAction === 'enable') + ) { + return false; + } else if (loadingRuleIds.length > 0) { + return true; + } + return false; + }, [loadingRuleIds, loadingRulesAction]); + return ( <> { + dispatch({ type: 'loadingRuleIds', ids: [], actionType: null }); dispatchToaster({ type: 'addToaster', toast: { @@ -256,22 +260,17 @@ export const AllRules = React.memo( /> - + <> - {((rulesCustomInstalled && rulesCustomInstalled > 0) || - (rulesInstalled != null && rulesInstalled > 0)) && ( - - - - )} - {isInitialLoad && ( - - )} - {isGlobalLoading && !isEmpty(tableData) && !isInitialLoad && ( + + + + + {(loading || isLoadingRules || isLoadingAnActionOnRule) && !initLoading && ( )} {rulesCustomInstalled != null && @@ -283,7 +282,10 @@ export const AllRules = React.memo( userHasNoPermissions={hasNoPermissions} /> )} - {showRulesTable({ isInitialLoad, rulesCustomInstalled, rulesInstalled }) && ( + {initLoading && ( + + )} + {showRulesTable({ rulesCustomInstalled, rulesInstalled }) && !initLoading && ( <> @@ -292,7 +294,7 @@ export const AllRules = React.memo( - {i18n.SELECTED_RULES(selectedItems.length)} + {i18n.SELECTED_RULES(selectedRuleIds.length)} {!hasNoPermissions && ( ( )} dispatch({ type: 'refresh' })} + onClick={() => reFetchRulesData(true)} > {i18n.REFRESH} - - ( totalItemCount: pagination.total, pageSizeOptions: [5, 10, 20, 50, 100, 200, 300], }} - sorting={{ sort: { field: 'activate', direction: filterOptions.sortOrder } }} + ref={tableRef} + sorting={{ sort: { field: 'enabled', direction: filterOptions.sortOrder } }} selection={hasNoPermissions ? undefined : euiBasicTableSelectionProps} /> diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/reducer.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/reducer.ts index 3634a16cbf6ac..54da43efd66d9 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/reducer.ts +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/reducer.ts @@ -4,34 +4,30 @@ * you may not use this file except in compliance with the Elastic License. */ +import { EuiBasicTable } from '@elastic/eui'; import { FilterOptions, PaginationOptions, Rule, } from '../../../../containers/detection_engine/rules'; -import { TableData } from '../types'; -import { formatRules } from './helpers'; +type LoadingRuleAction = 'duplicate' | 'enable' | 'disable' | 'export' | 'delete' | null; export interface State { - isLoading: boolean; - rules: Rule[]; - selectedItems: TableData[]; - pagination: PaginationOptions; + exportRuleIds: string[]; filterOptions: FilterOptions; - refreshToggle: boolean; - tableData: TableData[]; - exportPayload?: Rule[]; + loadingRuleIds: string[]; + loadingRulesAction: LoadingRuleAction; + pagination: PaginationOptions; + rules: Rule[]; + selectedRuleIds: string[]; } export type Action = - | { type: 'refresh' } - | { type: 'loading'; isLoading: boolean } - | { type: 'deleteRules'; rules: Rule[] } - | { type: 'duplicate'; rule: Rule } - | { type: 'setExportPayload'; exportPayload?: Rule[] } - | { type: 'setSelected'; selectedItems: TableData[] } - | { type: 'updateLoading'; ids: string[]; isLoading: boolean } - | { type: 'updateRules'; rules: Rule[]; pagination?: PaginationOptions } + | { type: 'exportRuleIds'; ids: string[] } + | { type: 'loadingRuleIds'; ids: string[]; actionType: LoadingRuleAction } + | { type: 'selectedRuleIds'; ids: string[] } + | { type: 'setRules'; rules: Rule[] } + | { type: 'updateRules'; rules: Rule[] } | { type: 'updatePagination'; pagination: Partial } | { type: 'updateFilterOptions'; @@ -40,54 +36,71 @@ export type Action = } | { type: 'failure' }; -export const allRulesReducer = (state: State, action: Action): State => { +export const allRulesReducer = ( + tableRef: React.MutableRefObject | undefined> +) => (state: State, action: Action): State => { switch (action.type) { - case 'refresh': { + case 'exportRuleIds': { return { ...state, - refreshToggle: !state.refreshToggle, + loadingRuleIds: action.ids, + loadingRulesAction: 'export', + exportRuleIds: action.ids, }; } - case 'updateRules': { - // If pagination included, this was a hard refresh - if (action.pagination) { - return { - ...state, - rules: action.rules, - pagination: action.pagination, - tableData: formatRules(action.rules), - }; + case 'loadingRuleIds': { + return { + ...state, + loadingRuleIds: action.actionType == null ? [] : [...state.loadingRuleIds, ...action.ids], + loadingRulesAction: action.actionType, + }; + } + case 'selectedRuleIds': { + return { + ...state, + selectedRuleIds: action.ids, + }; + } + case 'setRules': { + if ( + tableRef != null && + tableRef.current != null && + tableRef.current.changeSelection != null + ) { + tableRef.current.changeSelection([]); } - const ruleIds = state.rules.map(r => r.rule_id); - const updatedRules = action.rules.reverse().reduce((rules, updatedRule) => { - let newRules = rules; - if (ruleIds.includes(updatedRule.rule_id)) { - newRules = newRules.map(r => (updatedRule.rule_id === r.rule_id ? updatedRule : r)); - } else { - newRules = [...newRules, updatedRule]; - } - return newRules; - }, state.rules); - - // Update enabled on selectedItems so that batch actions show correct available actions - const updatedRuleIdToState = action.rules.reduce>( - (acc, r) => ({ ...acc, [r.id]: r.enabled }), - {} - ); - const updatedSelectedItems = state.selectedItems.map(selectedItem => - Object.keys(updatedRuleIdToState).includes(selectedItem.id) - ? { ...selectedItem, activate: updatedRuleIdToState[selectedItem.id] } - : selectedItem - ); - return { ...state, - rules: updatedRules, - tableData: formatRules(updatedRules), - selectedItems: updatedSelectedItems, + rules: action.rules, + selectedRuleIds: [], + loadingRuleIds: [], + loadingRulesAction: null, }; } + case 'updateRules': { + if (state.rules != null) { + const ruleIds = state.rules.map(r => r.id); + const updatedRules = action.rules.reduce((rules, updatedRule) => { + let newRules = rules; + if (ruleIds.includes(updatedRule.id)) { + newRules = newRules.map(r => (updatedRule.id === r.id ? updatedRule : r)); + } else { + newRules = [...newRules, updatedRule]; + } + return newRules; + }, state.rules); + const updatedRuleIds = action.rules.map(r => r.id); + const newLoadingRuleIds = state.loadingRuleIds.filter(id => !updatedRuleIds.includes(id)); + return { + ...state, + rules: updatedRules, + loadingRuleIds: newLoadingRuleIds, + loadingRulesAction: newLoadingRuleIds.length === 0 ? null : state.loadingRulesAction, + }; + } + return state; + } case 'updatePagination': { return { ...state, @@ -110,51 +123,12 @@ export const allRulesReducer = (state: State, action: Action): State => { }, }; } - case 'deleteRules': { - const deletedRuleIds = action.rules.map(r => r.rule_id); - const updatedRules = state.rules.reduce( - (rules, rule) => (deletedRuleIds.includes(rule.rule_id) ? rules : [...rules, rule]), - [] - ); - return { - ...state, - rules: updatedRules, - tableData: formatRules(updatedRules), - refreshToggle: !state.refreshToggle, - }; - } - case 'setSelected': { - return { - ...state, - selectedItems: action.selectedItems, - }; - } - case 'updateLoading': { - return { - ...state, - rules: state.rules, - tableData: formatRules(state.rules, action.ids), - }; - } - case 'loading': { - return { - ...state, - isLoading: action.isLoading, - }; - } case 'failure': { return { ...state, - isLoading: false, rules: [], }; } - case 'setExportPayload': { - return { - ...state, - exportPayload: [...(action.exportPayload ?? [])], - }; - } default: return state; } diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/rules_table_filters/rules_table_filters.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/rules_table_filters/rules_table_filters.tsx index fa4f6a874ca5e..ddb8894c206b5 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/rules_table_filters/rules_table_filters.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/rules_table_filters/rules_table_filters.tsx @@ -41,7 +41,11 @@ const RulesTableFiltersComponent = ({ const [selectedTags, setSelectedTags] = useState([]); const [showCustomRules, setShowCustomRules] = useState(false); const [showElasticRules, setShowElasticRules] = useState(false); - const [isLoadingTags, tags] = useTags(); + const [isLoadingTags, tags, reFetchTags] = useTags(); + + useEffect(() => { + reFetchTags(); + }, [rulesCustomInstalled, rulesInstalled]); // Propagate filter changes to parent useEffect(() => { diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_actions_overflow/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_actions_overflow/__snapshots__/index.test.tsx.snap index 9bd2fab23ac99..9355d0ae2cccb 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_actions_overflow/__snapshots__/index.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_actions_overflow/__snapshots__/index.test.tsx.snap @@ -58,6 +58,7 @@ exports[`RuleActionsOverflow renders correctly against snapshot 1`] = ` `; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_actions_overflow/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_actions_overflow/index.tsx index b52c10881cf42..7c8926c2064c7 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_actions_overflow/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_actions_overflow/index.tsx @@ -48,7 +48,7 @@ const RuleActionsOverflowComponent = ({ userHasNoPermissions, }: RuleActionsOverflowComponentProps) => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); - const [rulesToExport, setRulesToExport] = useState(undefined); + const [rulesToExport, setRulesToExport] = useState([]); const history = useHistory(); const [, dispatchToaster] = useStateToaster(); @@ -66,7 +66,7 @@ const RuleActionsOverflowComponent = ({ disabled={userHasNoPermissions} onClick={async () => { setIsPopoverOpen(false); - await duplicateRulesAction([rule], noop, dispatchToaster); + await duplicateRulesAction([rule], [rule.id], noop, dispatchToaster); }} > {i18nActions.DUPLICATE_RULE} @@ -75,9 +75,9 @@ const RuleActionsOverflowComponent = ({ key={i18nActions.EXPORT_RULE} icon="indexEdit" disabled={userHasNoPermissions || rule.immutable} - onClick={async () => { + onClick={() => { setIsPopoverOpen(false); - setRulesToExport([rule]); + setRulesToExport([rule.id]); }} > {i18nActions.EXPORT_RULE} @@ -131,7 +131,7 @@ const RuleActionsOverflowComponent = ({ { displaySuccessToast( i18nActions.SUCCESSFULLY_EXPORTED_RULES(exportCount), diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_downloader/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_downloader/index.tsx index b41265adea6b1..5d3086051a6e2 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_downloader/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_downloader/index.tsx @@ -7,7 +7,7 @@ import React, { useEffect, useRef } from 'react'; import styled from 'styled-components'; import { isFunction } from 'lodash/fp'; -import { exportRules, Rule } from '../../../../../containers/detection_engine/rules'; +import { exportRules } from '../../../../../containers/detection_engine/rules'; import { displayErrorToast, useStateToaster } from '../../../../../components/toasters'; import * as i18n from './translations'; @@ -17,7 +17,7 @@ const InvisibleAnchor = styled.a` export interface RuleDownloaderProps { filename: string; - rules?: Rule[]; + ruleIds?: string[]; onExportComplete: (exportCount: number) => void; } @@ -30,7 +30,7 @@ export interface RuleDownloaderProps { */ export const RuleDownloaderComponent = ({ filename, - rules, + ruleIds, onExportComplete, }: RuleDownloaderProps) => { const anchorRef = useRef(null); @@ -41,10 +41,10 @@ export const RuleDownloaderComponent = ({ const abortCtrl = new AbortController(); async function exportData() { - if (anchorRef && anchorRef.current && rules != null) { + if (anchorRef && anchorRef.current && ruleIds != null && ruleIds.length > 0) { try { const exportResponse = await exportRules({ - ruleIds: rules.map(r => r.rule_id), + ruleIds, signal: abortCtrl.signal, }); @@ -61,7 +61,7 @@ export const RuleDownloaderComponent = ({ window.URL.revokeObjectURL(objectURL); } - onExportComplete(rules.length); + onExportComplete(ruleIds.length); } } catch (error) { if (isSubscribed) { @@ -77,7 +77,7 @@ export const RuleDownloaderComponent = ({ isSubscribed = false; abortCtrl.abort(); }; - }, [rules]); + }, [ruleIds]); return ; }; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/index.tsx index 0c53ad19a3574..20185c2eda816 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/index.tsx @@ -26,11 +26,10 @@ import { UpdatePrePackagedRulesCallOut } from './components/pre_packaged_rules/u import { getPrePackagedRuleStatus, redirectToDetections } from './helpers'; import * as i18n from './translations'; -type Func = () => void; +type Func = (refreshPrePackagedRule?: boolean) => void; const RulesPageComponent: React.FC = () => { const [showImportModal, setShowImportModal] = useState(false); - const [importCompleteToggle, setImportCompleteToggle] = useState(false); const refreshRulesData = useRef(null); const { loading, @@ -67,14 +66,18 @@ const RulesPageComponent: React.FC = () => { const userHasNoPermissions = canUserCRUD != null && hasManageApiKey != null ? !canUserCRUD || !hasManageApiKey : false; + const handleRefreshRules = useCallback(async () => { + if (refreshRulesData.current != null) { + refreshRulesData.current(true); + } + }, [refreshRulesData]); + const handleCreatePrePackagedRules = useCallback(async () => { if (createPrePackagedRules != null) { await createPrePackagedRules(); - if (refreshRulesData.current != null) { - refreshRulesData.current(); - } + handleRefreshRules(); } - }, [createPrePackagedRules, refreshRulesData]); + }, [createPrePackagedRules, handleRefreshRules]); const handleRefetchPrePackagedRulesStatus = useCallback(() => { if (refetchPrePackagedRulesStatus != null) { @@ -96,7 +99,7 @@ const RulesPageComponent: React.FC = () => { setShowImportModal(false)} - importComplete={() => setImportCompleteToggle(!importCompleteToggle)} + importComplete={handleRefreshRules} /> { loading={loading || prePackagedRuleLoading} loadingCreatePrePackagedRules={loadingCreatePrePackagedRules} hasNoPermissions={userHasNoPermissions} - importCompleteToggle={importCompleteToggle} refetchPrePackagedRulesStatus={handleRefetchPrePackagedRulesStatus} rulesCustomInstalled={rulesCustomInstalled} rulesInstalled={rulesInstalled} diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/types.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/types.ts index 55eb45fb5ed9d..b2650dcc2b77e 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/types.ts +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/types.ts @@ -5,7 +5,6 @@ */ import { Filter } from '../../../../../../../../src/plugins/data/common'; -import { Rule } from '../../../containers/detection_engine/rules'; import { FieldValueQueryBar } from './components/query_bar'; import { FormData, FormHook } from '../../shared_imports'; import { FieldValueTimeline } from './components/pick_timeline'; @@ -23,24 +22,6 @@ export interface EuiBasicTableOnChange { sort?: EuiBasicTableSortTypes; } -export interface TableData { - id: string; - immutable: boolean; - rule_id: string; - rule: { - href: string; - name: string; - }; - risk_score: number; - severity: string; - tags: string[]; - activate: boolean; - isLoading: boolean; - sourceRule: Rule; - status?: string | null; - statusDate?: string | null; -} - export enum RuleStep { defineRule = 'define-rule', aboutRule = 'about-rule', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts index 51b7b132fc794..08a0589389966 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts @@ -5,7 +5,6 @@ */ import Hapi from 'hapi'; -import { countBy } from 'lodash/fp'; import uuid from 'uuid'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; @@ -45,8 +44,7 @@ export const createCreateRulesBulkRoute = ( } const ruleDefinitions = request.payload; - const mappedDuplicates = countBy('rule_id', ruleDefinitions); - const dupes = getDuplicates(mappedDuplicates); + const dupes = getDuplicates(ruleDefinitions, 'rule_id'); const rules = await Promise.all( ruleDefinitions diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts index b5b687c284b25..5fac3f79f359c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts @@ -20,7 +20,7 @@ import { } from './utils'; import { getResult } from '../__mocks__/request_responses'; import { INTERNAL_IDENTIFIER } from '../../../../../common/constants'; -import { OutputRuleAlertRest, ImportRuleAlertRest } from '../../types'; +import { OutputRuleAlertRest, ImportRuleAlertRest, RuleAlertParamsRest } from '../../types'; import { BulkError, ImportSuccessError } from '../utils'; import { sampleRule } from '../../signals/__mocks__/es_results'; import { getSimpleRule } from '../__mocks__/utils'; @@ -1222,20 +1222,32 @@ describe('utils', () => { describe('getDuplicates', () => { test("returns array of ruleIds showing the duplicate keys of 'value2' and 'value3'", () => { - const output = getDuplicates({ - value1: 1, - value2: 2, - value3: 2, - }); + const output = getDuplicates( + [ + { rule_id: 'value1' }, + { rule_id: 'value2' }, + { rule_id: 'value2' }, + { rule_id: 'value3' }, + { rule_id: 'value3' }, + {}, + {}, + ] as RuleAlertParamsRest[], + 'rule_id' + ); const expected = ['value2', 'value3']; expect(output).toEqual(expected); }); test('returns null when given a map of no duplicates', () => { - const output = getDuplicates({ - value1: 1, - value2: 1, - value3: 1, - }); + const output = getDuplicates( + [ + { rule_id: 'value1' }, + { rule_id: 'value2' }, + { rule_id: 'value3' }, + {}, + {}, + ] as RuleAlertParamsRest[], + 'rule_id' + ); const expected: string[] = []; expect(output).toEqual(expected); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts index ab80e1570c31c..7004bf2088ef2 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { pickBy } from 'lodash/fp'; -import { Dictionary } from 'lodash'; +import { pickBy, countBy } from 'lodash/fp'; import { SavedObject } from 'kibana/server'; import uuid from 'uuid'; import { INTERNAL_IDENTIFIER } from '../../../../../common/constants'; @@ -18,7 +17,7 @@ import { isRuleStatusFindTypes, isRuleStatusSavedObjectType, } from '../../rules/types'; -import { OutputRuleAlertRest, ImportRuleAlertRest } from '../../types'; +import { OutputRuleAlertRest, ImportRuleAlertRest, RuleAlertParamsRest } from '../../types'; import { createBulkErrorObject, BulkError, @@ -224,10 +223,14 @@ export const transformOrImportError = ( } }; -export const getDuplicates = (lodashDict: Dictionary): string[] => { - const hasDuplicates = Object.values(lodashDict).some(i => i > 1); +export const getDuplicates = (ruleDefinitions: RuleAlertParamsRest[], by: 'rule_id'): string[] => { + const mappedDuplicates = countBy( + by, + ruleDefinitions.filter(r => r[by] != null) + ); + const hasDuplicates = Object.values(mappedDuplicates).some(i => i > 1); if (hasDuplicates) { - return Object.keys(lodashDict).filter(key => lodashDict[key] > 1); + return Object.keys(mappedDuplicates).filter(key => mappedDuplicates[key] > 1); } return []; }; From 0e0f114d03f0becb9bbc5b93cbed217f2663efbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Wed, 26 Feb 2020 07:40:06 +0100 Subject: [PATCH 079/123] [APM] Improve debug output (#58467) --- .../apm/server/lib/helpers/es_client.ts | 96 +++++++++++-------- 1 file changed, 55 insertions(+), 41 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/helpers/es_client.ts b/x-pack/plugins/apm/server/lib/helpers/es_client.ts index 86eb1dba507f0..c22084dbb7168 100644 --- a/x-pack/plugins/apm/server/lib/helpers/es_client.ts +++ b/x-pack/plugins/apm/server/lib/helpers/es_client.ts @@ -12,8 +12,9 @@ import { IndicesCreateParams, DeleteDocumentResponse } from 'elasticsearch'; -import { cloneDeep, isString, merge, uniqueId } from 'lodash'; +import { cloneDeep, isString, merge } from 'lodash'; import { KibanaRequest } from 'src/core/server'; +import chalk from 'chalk'; import { ESSearchRequest, ESSearchResponse @@ -126,6 +127,10 @@ interface ClientCreateOptions { export type ESClient = ReturnType; +function formatObj(obj: Record) { + return JSON.stringify(obj, null, 2); +} + export function getESClient( context: APMRequestHandlerContext, request: KibanaRequest, @@ -136,25 +141,49 @@ export function getESClient( callAsInternalUser } = context.core.elasticsearch.dataClient; - const callMethod = clientAsInternalUser - ? callAsInternalUser - : callAsCurrentUser; + async function callEs(operationName: string, params: Record) { + const startTime = process.hrtime(); + + let res: any; + let esError = null; + try { + res = clientAsInternalUser + ? await callAsInternalUser(operationName, params) + : await callAsCurrentUser(operationName, params); + } catch (e) { + // catch error and throw after outputting debug info + esError = e; + } + + if (context.params.query._debug) { + const highlightColor = esError ? 'bgRed' : 'inverse'; + const diff = process.hrtime(startTime); + const duration = `${Math.round(diff[0] * 1000 + diff[1] / 1e6)}ms`; + const routeInfo = `${request.route.method.toUpperCase()} ${ + request.route.path + }`; - const debug = context.params.query._debug; + console.log( + chalk.bold[highlightColor](`=== Debug: ${routeInfo} (${duration}) ===`) + ); + + if (operationName === 'search') { + console.log(`GET ${params.index}/_${operationName}`); + console.log(formatObj(params.body)); + } else { + console.log(chalk.bold('ES operation:'), operationName); - function withTime( - fn: (log: typeof console.log) => Promise - ): Promise { - const log = console.log.bind(console, uniqueId()); - if (!debug) { - return fn(log); + console.log(chalk.bold('ES query:')); + console.log(formatObj(params)); + } + console.log(`\n`); } - const time = process.hrtime(); - return fn(log).then(data => { - const now = process.hrtime(time); - log(`took: ${Math.round(now[0] * 1000 + now[1] / 1e6)}ms`); - return data; - }); + + if (esError) { + throw esError; + } + + return res; } return { @@ -171,40 +200,25 @@ export function getESClient( apmOptions ); - return withTime(log => { - if (context.params.query._debug) { - log(`--DEBUG ES QUERY--`); - log( - `${request.url.pathname} ${JSON.stringify(context.params.query)}` - ); - log(`GET ${nextParams.index}/_search`); - log(JSON.stringify(nextParams.body, null, 2)); - } - - return (callMethod('search', nextParams) as unknown) as Promise< - ESSearchResponse - >; - }); + return callEs('search', nextParams); }, index: (params: APMIndexDocumentParams) => { - return withTime(() => callMethod('index', params)); + return callEs('index', params); }, delete: (params: IndicesDeleteParams): Promise => { - return withTime(() => callMethod('delete', params)); + return callEs('delete', params); }, indicesCreate: (params: IndicesCreateParams) => { - return withTime(() => callMethod('indices.create', params)); + return callEs('indices.create', params); }, hasPrivileges: ( params: IndexPrivilegesParams ): Promise => { - return withTime(() => - callMethod('transport.request', { - method: 'POST', - path: '/_security/user/_has_privileges', - body: params - }) - ); + return callEs('transport.request', { + method: 'POST', + path: '/_security/user/_has_privileges', + body: params + }); } }; } From 71254de3c2b94bf1185a27723939de32e4945497 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 26 Feb 2020 09:21:32 +0000 Subject: [PATCH 080/123] [ML] Adding get records endpoint wrapper (#58500) --- .../ml/server/client/elasticsearch_ml.js | 12 +++++ .../ml/server/routes/anomaly_detectors.ts | 48 ++++++++++++++++++- .../plugins/ml/server/routes/apidoc.json | 2 + 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/ml/server/client/elasticsearch_ml.js b/x-pack/legacy/plugins/ml/server/client/elasticsearch_ml.js index 9317d3c6c3e07..e3092abb5d34e 100644 --- a/x-pack/legacy/plugins/ml/server/client/elasticsearch_ml.js +++ b/x-pack/legacy/plugins/ml/server/client/elasticsearch_ml.js @@ -450,6 +450,18 @@ export const elasticsearchJsPlugin = (Client, config, components) => { method: 'POST', }); + ml.records = ca({ + url: { + fmt: '/_ml/anomaly_detectors/<%=jobId%>/results/records', + req: { + jobId: { + type: 'string', + }, + }, + }, + method: 'POST', + }); + ml.buckets = ca({ urls: [ { diff --git a/x-pack/legacy/plugins/ml/server/routes/anomaly_detectors.ts b/x-pack/legacy/plugins/ml/server/routes/anomaly_detectors.ts index 927646e4f0acc..99dbdec9e945b 100644 --- a/x-pack/legacy/plugins/ml/server/routes/anomaly_detectors.ts +++ b/x-pack/legacy/plugins/ml/server/routes/anomaly_detectors.ts @@ -376,11 +376,57 @@ export function jobRoutes({ xpackMainPlugin, router }: RouteInitialization) { }) ); + /** + * @apiGroup AnomalyDetectors + * + * @api {post} /api/ml/anomaly_detectors/:jobId/results/records Retrieves anomaly records for a job. + * @apiName GetRecords + * @apiDescription Retrieves anomaly records for a job. + * + * @apiParam {String} jobId Job ID. + * + * @apiSuccess {Number} count + * @apiSuccess {Object[]} records + */ + router.post( + { + path: '/api/ml/anomaly_detectors/{jobId}/results/records', + validate: { + params: schema.object({ + jobId: schema.string(), + }), + body: schema.object({ + desc: schema.maybe(schema.boolean()), + end: schema.maybe(schema.string()), + exclude_interim: schema.maybe(schema.boolean()), + 'page.from': schema.maybe(schema.number()), + 'page.size': schema.maybe(schema.number()), + record_score: schema.maybe(schema.number()), + sort: schema.maybe(schema.string()), + start: schema.maybe(schema.string()), + }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const results = await context.ml!.mlClient.callAsCurrentUser('ml.records', { + jobId: request.params.jobId, + ...request.body, + }); + return response.ok({ + body: results, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + /** * @apiGroup AnomalyDetectors * * @api {post} /api/ml/anomaly_detectors/:jobId/results/buckets Obtain bucket scores for the specified job ID - * @apiName GetOverallBuckets + * @apiName GetBuckets * @apiDescription The get buckets API presents a chronological view of the records, grouped by bucket. * * @apiParam {String} jobId Job ID. diff --git a/x-pack/legacy/plugins/ml/server/routes/apidoc.json b/x-pack/legacy/plugins/ml/server/routes/apidoc.json index 946e3bd71d6c3..c5aa3e4d792fd 100644 --- a/x-pack/legacy/plugins/ml/server/routes/apidoc.json +++ b/x-pack/legacy/plugins/ml/server/routes/apidoc.json @@ -31,6 +31,8 @@ "DeleteAnomalyDetectorsJob", "ValidateAnomalyDetector", "ForecastAnomalyDetector", + "GetRecords", + "GetBuckets", "GetOverallBuckets", "GetCategories", "FileDataVisualizer", From a4e82c4e6d9b30d017b290f9d3abbded84f0d3ac Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Wed, 26 Feb 2020 10:39:16 +0100 Subject: [PATCH 081/123] Adapt es-archiver to call `_migrate` endpoint instead of creating a migrator (#56971) * es-archiver call _migrate endpoint instead of creating a migrator * fix crlf.... * use promise instead of callback accessor * attempt with disabled authent * enable security again * set mapping to dynamic before calling migration endpoint * rename space data from non-spaced tests * add documentation on the `rerun` flag * create router with the `/api/saved_objects` prefix * add unit test about strict mapping * add integration test on migrate endpoint * wrap route handler with handleLegacyErrors * add remark about limitations of the rerun flag * Apply suggestions from code review Co-Authored-By: Aleh Zasypkin * do not return detailed index result * add access tag to migrate route * use /internal prefix for migrate endpoint * fix integ tests Co-authored-by: Elastic Machine Co-authored-by: Josh Dover Co-authored-by: Aleh Zasypkin --- .../kbn_client/kbn_client_saved_objects.ts | 19 ++++ packages/kbn-pm/dist/index.js | 12 +++ .../core/build_active_mappings.test.ts | 5 + .../migrations/kibana/kibana_migrator.ts | 18 +++- src/core/server/saved_objects/routes/index.ts | 8 ++ .../routes/integration_tests/import.test.ts | 14 +-- .../integration_tests/migrate.test.mocks.ts | 26 +++++ .../routes/integration_tests/migrate.test.ts | 62 ++++++++++++ .../server/saved_objects/routes/migrate.ts | 45 +++++++++ .../saved_objects/saved_objects_service.ts | 13 ++- src/es_archiver/actions/empty_kibana_index.ts | 3 +- src/es_archiver/actions/load.ts | 2 +- src/es_archiver/lib/indices/kibana_index.ts | 94 ++---------------- .../reporting/ecommerce/data.json.gz | Bin 1007039 -> 1007932 bytes .../reporting/ecommerce_kibana/data.json.gz | Bin 2132 -> 2039 bytes .../es_archives/reporting/nanos/data.json.gz | Bin 982 -> 863 bytes 16 files changed, 221 insertions(+), 100 deletions(-) create mode 100644 src/core/server/saved_objects/routes/integration_tests/migrate.test.mocks.ts create mode 100644 src/core/server/saved_objects/routes/integration_tests/migrate.test.ts create mode 100644 src/core/server/saved_objects/routes/migrate.ts diff --git a/packages/kbn-dev-utils/src/kbn_client/kbn_client_saved_objects.ts b/packages/kbn-dev-utils/src/kbn_client/kbn_client_saved_objects.ts index 51fa19c140bf0..e671061b34352 100644 --- a/packages/kbn-dev-utils/src/kbn_client/kbn_client_saved_objects.ts +++ b/packages/kbn-dev-utils/src/kbn_client/kbn_client_saved_objects.ts @@ -57,9 +57,28 @@ interface UpdateOptions extends IndexOptions { id: string; } +interface MigrateResponse { + success: boolean; + result: Array<{ status: string }>; +} + export class KbnClientSavedObjects { constructor(private readonly log: ToolingLog, private readonly requester: KbnClientRequester) {} + /** + * Run the saved objects migration + */ + public async migrate() { + this.log.debug('Migrating saved objects'); + + return await this.requester.request({ + description: 'migrate saved objects', + path: uriencode`/internal/saved_objects/_migrate`, + method: 'POST', + body: {}, + }); + } + /** * Get an object */ diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 451db9750ada7..fe0491870e4bd 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -43784,6 +43784,18 @@ class KbnClientSavedObjects { this.log = log; this.requester = requester; } + /** + * Run the saved objects migration + */ + async migrate() { + this.log.debug('Migrating saved objects'); + return await this.requester.request({ + description: 'migrate saved objects', + path: kbn_client_requester_1.uriencode `/internal/saved_objects/_migrate`, + method: 'POST', + body: {}, + }); + } /** * Get an object */ diff --git a/src/core/server/saved_objects/migrations/core/build_active_mappings.test.ts b/src/core/server/saved_objects/migrations/core/build_active_mappings.test.ts index 821a10353f8ec..9d220cfdf94b7 100644 --- a/src/core/server/saved_objects/migrations/core/build_active_mappings.test.ts +++ b/src/core/server/saved_objects/migrations/core/build_active_mappings.test.ts @@ -21,6 +21,11 @@ import { IndexMapping } from './../../mappings'; import { buildActiveMappings, diffMappings } from './build_active_mappings'; describe('buildActiveMappings', () => { + test('creates a strict mapping', () => { + const mappings = buildActiveMappings({}); + expect(mappings.dynamic).toEqual('strict'); + }); + test('combines all mappings and includes core mappings', () => { const properties = { aaa: { type: 'text' }, diff --git a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts index 494f834717def..bc29061b380b8 100644 --- a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts +++ b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts @@ -88,15 +88,27 @@ export class KibanaMigrator { } /** - * Migrates the mappings and documents in the Kibana index. This will run only + * Migrates the mappings and documents in the Kibana index. By default, this will run only * once and subsequent calls will return the result of the original call. * + * @param rerun - If true, method will run a new migration when called again instead of + * returning the result of the initial migration. This should only be used when factors external + * to Kibana itself alter the kibana index causing the saved objects mappings or data to change + * after the Kibana server performed the initial migration. + * + * @remarks When the `rerun` parameter is set to true, no checks are performed to ensure that no migration + * is currently running. Chained or concurrent calls to `runMigrations({ rerun: true })` can lead to + * multiple migrations running at the same time. When calling with this parameter, it's expected that the calling + * code should ensure that the initial call resolves before calling the function again. + * * @returns - A promise which resolves once all migrations have been applied. * The promise resolves with an array of migration statuses, one for each * elasticsearch index which was migrated. */ - public runMigrations(): Promise> { - if (this.migrationResult === undefined) { + public runMigrations({ rerun = false }: { rerun?: boolean } = {}): Promise< + Array<{ status: string }> + > { + if (this.migrationResult === undefined || rerun) { this.migrationResult = this.runMigrationsInternal(); } diff --git a/src/core/server/saved_objects/routes/index.ts b/src/core/server/saved_objects/routes/index.ts index f2f57798dd5f0..0afa24b18760b 100644 --- a/src/core/server/saved_objects/routes/index.ts +++ b/src/core/server/saved_objects/routes/index.ts @@ -20,6 +20,7 @@ import { InternalHttpServiceSetup } from '../../http'; import { Logger } from '../../logging'; import { SavedObjectConfig } from '../saved_objects_config'; +import { IKibanaMigrator } from '../migrations'; import { registerGetRoute } from './get'; import { registerCreateRoute } from './create'; import { registerDeleteRoute } from './delete'; @@ -32,17 +33,20 @@ import { registerLogLegacyImportRoute } from './log_legacy_import'; import { registerExportRoute } from './export'; import { registerImportRoute } from './import'; import { registerResolveImportErrorsRoute } from './resolve_import_errors'; +import { registerMigrateRoute } from './migrate'; export function registerRoutes({ http, logger, config, importableExportableTypes, + migratorPromise, }: { http: InternalHttpServiceSetup; logger: Logger; config: SavedObjectConfig; importableExportableTypes: string[]; + migratorPromise: Promise; }) { const router = http.createRouter('/api/saved_objects/'); @@ -58,4 +62,8 @@ export function registerRoutes({ registerExportRoute(router, config, importableExportableTypes); registerImportRoute(router, config, importableExportableTypes); registerResolveImportErrorsRoute(router, config, importableExportableTypes); + + const internalRouter = http.createRouter('/internal/saved_objects/'); + + registerMigrateRoute(internalRouter, migratorPromise); } diff --git a/src/core/server/saved_objects/routes/integration_tests/import.test.ts b/src/core/server/saved_objects/routes/integration_tests/import.test.ts index 2c8d568b750c6..954e6d9e4831a 100644 --- a/src/core/server/saved_objects/routes/integration_tests/import.test.ts +++ b/src/core/server/saved_objects/routes/integration_tests/import.test.ts @@ -32,7 +32,7 @@ const config = { maxImportExportSize: 10000, } as SavedObjectConfig; -describe('POST /api/saved_objects/_import', () => { +describe('POST /internal/saved_objects/_import', () => { let server: setupServerReturn['server']; let httpSetup: setupServerReturn['httpSetup']; let handlerContext: setupServerReturn['handlerContext']; @@ -51,7 +51,7 @@ describe('POST /api/saved_objects/_import', () => { savedObjectsClient.find.mockResolvedValue(emptyResponse); - const router = httpSetup.createRouter('/api/saved_objects/'); + const router = httpSetup.createRouter('/internal/saved_objects/'); registerImportRoute(router, config, allowedTypes); await server.start(); @@ -63,7 +63,7 @@ describe('POST /api/saved_objects/_import', () => { it('formats successful response', async () => { const result = await supertest(httpSetup.server.listener) - .post('/api/saved_objects/_import') + .post('/internal/saved_objects/_import') .set('content-Type', 'multipart/form-data; boundary=BOUNDARY') .send( [ @@ -99,7 +99,7 @@ describe('POST /api/saved_objects/_import', () => { }); const result = await supertest(httpSetup.server.listener) - .post('/api/saved_objects/_import') + .post('/internal/saved_objects/_import') .set('content-Type', 'multipart/form-data; boundary=EXAMPLE') .send( [ @@ -148,7 +148,7 @@ describe('POST /api/saved_objects/_import', () => { }); const result = await supertest(httpSetup.server.listener) - .post('/api/saved_objects/_import') + .post('/internal/saved_objects/_import') .set('content-Type', 'multipart/form-data; boundary=EXAMPLE') .send( [ @@ -199,7 +199,7 @@ describe('POST /api/saved_objects/_import', () => { }); const result = await supertest(httpSetup.server.listener) - .post('/api/saved_objects/_import') + .post('/internal/saved_objects/_import') .set('content-Type', 'multipart/form-data; boundary=EXAMPLE') .send( [ @@ -249,7 +249,7 @@ describe('POST /api/saved_objects/_import', () => { }); const result = await supertest(httpSetup.server.listener) - .post('/api/saved_objects/_import') + .post('/internal/saved_objects/_import') .set('content-Type', 'multipart/form-data; boundary=EXAMPLE') .send( [ diff --git a/src/core/server/saved_objects/routes/integration_tests/migrate.test.mocks.ts b/src/core/server/saved_objects/routes/integration_tests/migrate.test.mocks.ts new file mode 100644 index 0000000000000..870d50426904f --- /dev/null +++ b/src/core/server/saved_objects/routes/integration_tests/migrate.test.mocks.ts @@ -0,0 +1,26 @@ +/* + * 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 { mockKibanaMigrator } from '../../migrations/kibana/kibana_migrator.mock'; + +export const migratorInstanceMock = mockKibanaMigrator.create(); +export const KibanaMigratorMock = jest.fn().mockImplementation(() => migratorInstanceMock); +jest.doMock('../../migrations/kibana/kibana_migrator', () => ({ + KibanaMigrator: KibanaMigratorMock, +})); diff --git a/src/core/server/saved_objects/routes/integration_tests/migrate.test.ts b/src/core/server/saved_objects/routes/integration_tests/migrate.test.ts new file mode 100644 index 0000000000000..928d17e7e5be2 --- /dev/null +++ b/src/core/server/saved_objects/routes/integration_tests/migrate.test.ts @@ -0,0 +1,62 @@ +/* + * 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 { migratorInstanceMock } from './migrate.test.mocks'; +import * as kbnTestServer from '../../../../../test_utils/kbn_server'; + +describe('SavedObjects /_migrate endpoint', () => { + let root: ReturnType; + + beforeEach(async () => { + root = kbnTestServer.createRoot({ migrations: { skip: true } }); + await root.setup(); + await root.start(); + migratorInstanceMock.runMigrations.mockClear(); + }, 30000); + + afterEach(async () => { + await root.shutdown(); + }); + + it('calls runMigrations on the migrator with rerun=true when accessed', async () => { + await kbnTestServer.request + .post(root, '/internal/saved_objects/_migrate') + .send({}) + .expect(200); + + expect(migratorInstanceMock.runMigrations).toHaveBeenCalledTimes(1); + expect(migratorInstanceMock.runMigrations).toHaveBeenCalledWith({ rerun: true }); + }); + + it('calls runMigrations multiple time when multiple access', async () => { + await kbnTestServer.request + .post(root, '/internal/saved_objects/_migrate') + .send({}) + .expect(200); + + expect(migratorInstanceMock.runMigrations).toHaveBeenCalledTimes(1); + + await kbnTestServer.request + .post(root, '/internal/saved_objects/_migrate') + .send({}) + .expect(200); + + expect(migratorInstanceMock.runMigrations).toHaveBeenCalledTimes(2); + }); +}); diff --git a/src/core/server/saved_objects/routes/migrate.ts b/src/core/server/saved_objects/routes/migrate.ts new file mode 100644 index 0000000000000..69e99d10acd09 --- /dev/null +++ b/src/core/server/saved_objects/routes/migrate.ts @@ -0,0 +1,45 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IRouter } from '../../http'; +import { IKibanaMigrator } from '../migrations'; + +export const registerMigrateRoute = ( + router: IRouter, + migratorPromise: Promise +) => { + router.post( + { + path: '/_migrate', + validate: false, + options: { + tags: ['access:migrateSavedObjects'], + }, + }, + router.handleLegacyErrors(async (context, req, res) => { + const migrator = await migratorPromise; + await migrator.runMigrations({ rerun: true }); + return res.ok({ + body: { + success: true, + }, + }); + }) + ); +}; diff --git a/src/core/server/saved_objects/saved_objects_service.ts b/src/core/server/saved_objects/saved_objects_service.ts index ece00539536e1..fa2b67a3e43b2 100644 --- a/src/core/server/saved_objects/saved_objects_service.ts +++ b/src/core/server/saved_objects/saved_objects_service.ts @@ -17,8 +17,9 @@ * under the License. */ -import { CoreService } from 'src/core/types'; +import { Subject } from 'rxjs'; import { first, filter, take } from 'rxjs/operators'; +import { CoreService } from '../../types'; import { SavedObjectsClient, SavedObjectsClientProvider, @@ -36,7 +37,7 @@ import { SavedObjectsMigrationConfigType, SavedObjectConfig, } from './saved_objects_config'; -import { InternalHttpServiceSetup, KibanaRequest } from '../http'; +import { KibanaRequest, InternalHttpServiceSetup } from '../http'; import { SavedObjectsClientContract, SavedObjectsType, SavedObjectsLegacyUiExports } from './types'; import { ISavedObjectsRepository, SavedObjectsRepository } from './service/lib/repository'; import { @@ -47,8 +48,8 @@ import { Logger } from '../logging'; import { convertLegacyTypes } from './utils'; import { SavedObjectTypeRegistry, ISavedObjectTypeRegistry } from './saved_objects_type_registry'; import { PropertyValidators } from './validation'; -import { registerRoutes } from './routes'; import { SavedObjectsSerializer } from './serialization'; +import { registerRoutes } from './routes'; /** * Saved Objects is Kibana's data persistence mechanism allowing plugins to @@ -201,9 +202,9 @@ export interface SavedObjectsRepositoryFactory { /** @internal */ export interface SavedObjectsSetupDeps { + http: InternalHttpServiceSetup; legacyPlugins: LegacyServiceDiscoverPlugins; elasticsearch: InternalElasticsearchServiceSetup; - http: InternalHttpServiceSetup; } interface WrappedClientFactoryWrapper { @@ -225,6 +226,7 @@ export class SavedObjectsService private clientFactoryProvider?: SavedObjectsClientFactoryProvider; private clientFactoryWrappers: WrappedClientFactoryWrapper[] = []; + private migrator$ = new Subject(); private typeRegistry = new SavedObjectTypeRegistry(); private validations: PropertyValidators = {}; @@ -262,6 +264,7 @@ export class SavedObjectsService http: setupDeps.http, logger: this.logger, config: this.config, + migratorPromise: this.migrator$.pipe(first()).toPromise(), importableExportableTypes, }); @@ -302,6 +305,8 @@ export class SavedObjectsService const adminClient = this.setupDeps!.elasticsearch.adminClient; const migrator = this.createMigrator(kibanaConfig, this.config.migration, migrationsRetryDelay); + this.migrator$.next(migrator); + /** * Note: We want to ensure that migrations have completed before * continuing with further Core start steps that might use SavedObjects diff --git a/src/es_archiver/actions/empty_kibana_index.ts b/src/es_archiver/actions/empty_kibana_index.ts index 5f96fbc5f996c..d61d544deadc4 100644 --- a/src/es_archiver/actions/empty_kibana_index.ts +++ b/src/es_archiver/actions/empty_kibana_index.ts @@ -32,9 +32,8 @@ export async function emptyKibanaIndexAction({ kbnClient: KbnClient; }) { const stats = createStats('emptyKibanaIndex', log); - const kibanaPluginIds = await kbnClient.plugins.getEnabledIds(); await deleteKibanaIndices({ client, stats, log }); - await migrateKibanaIndex({ client, log, kibanaPluginIds }); + await migrateKibanaIndex({ client, kbnClient }); return stats; } diff --git a/src/es_archiver/actions/load.ts b/src/es_archiver/actions/load.ts index 404fd0daea91d..ae7799205b299 100644 --- a/src/es_archiver/actions/load.ts +++ b/src/es_archiver/actions/load.ts @@ -106,7 +106,7 @@ export async function loadAction({ // If we affected the Kibana index, we need to ensure it's migrated... if (Object.keys(result).some(k => k.startsWith('.kibana'))) { - await migrateKibanaIndex({ client, log, kibanaPluginIds }); + await migrateKibanaIndex({ client, kbnClient }); if (kibanaPluginIds.includes('spaces')) { await createDefaultSpace({ client, index: '.kibana' }); diff --git a/src/es_archiver/lib/indices/kibana_index.ts b/src/es_archiver/lib/indices/kibana_index.ts index 56be86a23eda0..1867f24d6f9ed 100644 --- a/src/es_archiver/lib/indices/kibana_index.ts +++ b/src/es_archiver/lib/indices/kibana_index.ts @@ -17,42 +17,10 @@ * under the License. */ -import { get } from 'lodash'; -import fs from 'fs'; -import Path from 'path'; -import { promisify } from 'util'; -import { toArray } from 'rxjs/operators'; import { Client, CreateDocumentParams } from 'elasticsearch'; -import { ToolingLog } from '@kbn/dev-utils'; - +import { ToolingLog, KbnClient } from '@kbn/dev-utils'; import { Stats } from '../stats'; import { deleteIndex } from './delete_index'; -import { KibanaMigrator } from '../../../core/server/saved_objects/migrations'; -import { LegacyConfig } from '../../../core/server'; -import { convertLegacyTypes } from '../../../core/server/saved_objects/utils'; -import { SavedObjectTypeRegistry } from '../../../core/server/saved_objects'; -// @ts-ignore -import { collectUiExports } from '../../../legacy/ui/ui_exports'; -// @ts-ignore -import { findPluginSpecs } from '../../../legacy/plugin_discovery'; - -/** - * Load the uiExports for a Kibana instance, only load uiExports from xpack if - * it is enabled in the Kibana server. - */ -const getUiExports = async (kibanaPluginIds: string[]) => { - const xpackEnabled = kibanaPluginIds.includes('xpack_main'); - - const { spec$ } = await findPluginSpecs({ - plugins: { - scanDirs: [Path.resolve(__dirname, '../../../legacy/core_plugins')], - paths: xpackEnabled ? [Path.resolve(__dirname, '../../../../x-pack')] : [], - }, - }); - - const specs = await spec$.pipe(toArray()).toPromise(); - return collectUiExports(specs); -}; /** * Deletes all indices that start with `.kibana` @@ -93,61 +61,21 @@ export async function deleteKibanaIndices({ */ export async function migrateKibanaIndex({ client, - log, - kibanaPluginIds, + kbnClient, }: { client: Client; - log: ToolingLog; - kibanaPluginIds: string[]; + kbnClient: KbnClient; }) { - const uiExports = await getUiExports(kibanaPluginIds); - const kibanaVersion = await loadKibanaVersion(); - - const configKeys: Record = { - 'xpack.task_manager.index': '.kibana_task_manager', - }; - const config = { get: (path: string) => configKeys[path] }; - - const savedObjectTypes = convertLegacyTypes(uiExports, config as LegacyConfig); - const typeRegistry = new SavedObjectTypeRegistry(); - savedObjectTypes.forEach(type => typeRegistry.registerType(type)); - - const logger = { - trace: log.verbose.bind(log), - debug: log.debug.bind(log), - info: log.info.bind(log), - warn: log.warning.bind(log), - error: log.error.bind(log), - fatal: log.error.bind(log), - log: (entry: any) => log.info(entry.message), - get: () => logger, - }; - - const migratorOptions = { - savedObjectsConfig: { - scrollDuration: '5m', - batchSize: 100, - pollInterval: 100, - skip: false, + // we allow dynamic mappings on the index, as some interceptors are accessing documents before + // the migration is actually performed. The migrator will put the value back to `strict` after migration. + await client.indices.putMapping({ + index: '.kibana', + body: { + dynamic: true, }, - kibanaConfig: { - index: '.kibana', - } as any, - logger, - kibanaVersion, - typeRegistry, - savedObjectValidations: uiExports.savedObjectValidations, - callCluster: (path: string, ...args: any[]) => - (get(client, path) as Function).call(client, ...args), - }; - - return await new KibanaMigrator(migratorOptions).runMigrations(); -} + } as any); -async function loadKibanaVersion() { - const readFile = promisify(fs.readFile); - const packageJson = await readFile(Path.join(__dirname, '../../../../package.json')); - return JSON.parse(packageJson.toString('utf-8')).version; + return await kbnClient.savedObjects.migrate(); } /** diff --git a/x-pack/test/functional/es_archives/reporting/ecommerce/data.json.gz b/x-pack/test/functional/es_archives/reporting/ecommerce/data.json.gz index b38981c03417e2d6393878ec6ba719f1c2822588..58ac5616651d418e55f05da71976467b171aa390 100644 GIT binary patch literal 1007932 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�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�^|;run9RC}2+t@{$eg(frO&5O*vDm-f&m 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

W#ldv}5E$L=861~F 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

eM8X_9D$Z5TuX_Nk3@9W$&p` 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�vYwRwQm zZ2vdh&?;0WFvSd*S9A!!O6jL8IGFQ_w=ypn)bEWXo7vxJ2%NWi{t6(AFu+-ED;Bn> z$y@FXm~Q@Y2V+y``S%VBSJE7L#Yk-nYY?FP1k9|cq0&S-ow-eT7;{%2-c+|yk&$`ZR-UoEV z_)oC2v5^Q2BJxX3m30iMOGmOrfhtHNBh;BDp^Y`;9xP}c%;@v*pYo+4ui!Pl_v>$5 zAL{xvG_Z#DYSQ`P@&ItYuIiBU*)#thO7v)|J7*B>mXE)5r_=zLK;JCoq_2=E-H7M* zX&s9+gbTH_0Z0n2&wICxH@mk~zW9=OMd5PG?OHeb={*+vw8XWC(+D;0Z42Myh-%vK zEJxo-D7#3)yQ<3*aox2~{_6i@k9Wkx-+wLd2ogAEc@r?dh#J(>I2v-BoS5x~KJ*q)i{_q;Noz>e$OhRk?}+ z4T?}X*o0rX${S)|mQM`}mg(5q5f;%(jz}aQWy(~(pr@*r2bC|wB>%rdBv%!Ap_{^L>b@z{M zwf-ymahAJprN%=eAD_=A<7*IHo6J-=55HgvD){}{tt)%CH#_K7_T=2G8a4-X87(%z z!?B3dE4GTZwkU+kYvicdDmr!zMzO~U0-)259{l3-d9+wsVeK*dsdIUU0^ZPJ7&@I< zsOF*l@`aJ9uFgN<7;$K`f7`S-El|V(|F@7w6UonA*FU5=8mZ|nY?t7{Cp$-bkna-+ z)w1+tl_`LCYU?`JUUl566uvI@`rv>Vbn`~&+cDr`d??ri-?d=m1b5$CqcDhL-9ser zcVG|=G`g|V4HnBuE$aoN;=sd=aEqZsSD4iTbR_ZaE9I8LXvR45IJ@WdsDWBW9i(B* zQR<|})Fp9$G%yW+r!+i2(&!7gmANIo4HLCHzpo>l#xnc%sPaQs45LJUzS&AfXT z^zLICRdW%7&duuoDA^@FWgC6)u8FeubhiZe#+)h@?&f$OWZ!1l>6{=R0k;4^K(|$V zZ}t70MsVxn&Ram+{Prora3b8u?lqkRZH|*{~k3LZ0izqo{sA+sAQE1SWA6Xel zHT?ZvX&ulMU_PO}7z`w2unu!vlP#&pJD1I<^f1xoLSFVOZPb+}bVeRj3dJdA_*9X6*du)`~VjO z1ngxOHpA_rThLSpEl!9`OGA{ggh96ShvS4C{+`3!a@^qFd z7LMPw=cGNr4#-tUgnp8@>uyztRJP8cX3DmNZ!`{}a{ zZJnRNmOsAi^U^KD>aR3yOWCGc=8h~c1qE343J6VnO1&V&S!Q~=NYg3?K5Gn7_m2#| zO5c=*#rwSVsZOb6(8en2^+rpc2wEjY;U>4wa;&^UZVz>#PZCziY}eN!SoNPf&3ET;UAzqx5fAc z!Q;5wBcg-bdyW1QpTmfab62r)8kK$BW%t)_)vX&)o9f)XvU6RVFydgWjhb)xq9NU) zK@FfrX5#T!1OaCh>zL@LC}cGuZJ~~<%mWSpmdBrJv=gnxF?gT5WV@Ff+1^@b~T(LDe5ZChmyM5ciFbvcMu7)|Tl5(7A zJKA{s>L0!LqqH%tU9>utbjfUy$xg{Dl!fhBwF<>;_3PmY?I}+B8_|f@{4GiaI2k#y zS~0`Zn^GpLcAKd8YmH4Tl;xOswh?fVxjRtBR}V&o0|6dFT9NQvAb}qvKX-gK&5v2% zSUjZ5z93Cb_8pBQlVH-|8ry6&E-MVbBcH$^0_du&2=H%1i&bVNU|XH^c9(u+sR|vH z$(H+;A&S|6!?av7e`szo`1k$p-abn@4k)ZZx>}>5Se#2~f_{zCp|Ng3%CsjA(JD*$ z*p3o8x~!R;ZRxWKcpC~v5Ado5|7@Vn$gx`d3Yv6!7<-2dv*&#y4YvlIV)=hzJEC8C zq#kZyL2VZWdO^(>{b~`f7&a>z@bu8@RUc38jRHclTkZQjv0d>mn=IYA*bD^12Z^vR z&r!2u$m_&C*>N<*gCDw_5kr>Dbfq9RwqUu46Rc`6&nm2xXV=RN0uEhB z3+UthS?#w`lMW42ak!f^7<@C8`6-J^5!0qGUC?aH0#6&^aQj2rX$nm5phYU5hX=|R zhSIZTG0Jq!V>|_3lz_(&`~)~Q-?eslSA0K@%@QOQ%XUr^4)gMTlA$g#2HWjWkA8bczX^wh%x07pKj5o6Cu43p694q=bP zq9W;?smYM($d<)%pODHM%)ibI&us{3n|^+kkyiz_83?krlUHAdvllqq7Grn#JDjJF zj{as^9DGpt0t?sb@f)n}8$NhUoeb{d}PUs!aMOTmAwPRzJdzWeSS<2U6`g1E*x@#${ z`RKjdKV$Vlf67x$ht*@Q+vi5LE zqy)fq?Qhyk6kw3boNv<(EgkArTG7(b92er4=9c`TCh4J&)m>MPCiEwqB)&$CbgL?B zF4&0E9Iku*#=JGH)g`)+TH3%~O?FpY3@9uYD)tmVm+2`)93%N3*1$&EeUj2v^_f@2 zO}!3QUD1lWO}{tOZTr|?>=!JKKQyKE8(d zSSgpd;Wylh3}p!A!e-S__W>0)K&-I%ot&dYFBwS5E68YGfm%8JWQu^y4dM2N0;PV- z_ceV>o&h!Tg=WNg+vr%6=Tvn+DrQ~NhRkFKZ0Y0>vyEj#!3}h1clUDwqR;on9cE|` z6%4+3AT9sD>9hnEss21Rw`a}kd2e5HFn!m(QD>7S%Zm@?zt0(1#x4`#&D@|z$)i8( zg>w5Q!b_#2m*qt#?KbAWil?Z_%f~po6^|2EBvbc>^d+Wt(?W1%Q6)yipR>)>*uVlo z1h#TqZAblIb2g`&viGQe;&5#IGn7t zO*U`M+ypCZq(uoxaCGEKnsI%d6jEkbk2lo>nQCse%fH*ekWvgGhbbb@ zUjKCWWPX<^b(>@njhRc~pX1TA%;(Gm%G3x}LL@X_HHdgv(^}1E3SJNT{yX9E;E*2} zF%Z0U0p1|ij%kJ5vq`Ql^U@~8DiW5aE83q7ujPaJ#G_rEh_jd8n`u&(rq?=os(caH zFUg!?Fs|;>2-F8+?pO)H*GTXf-)oAvb+?>c6K!h@Z(Bhh5|_Y%nQK2?@9#IyF+dt1 zPN>eY@{J_)LVmT1&dJsKEkPId5zD z-auU8vo51~hYv-^)FkILmUC>))QhLfrPiZmam)A1<8+kYZU{0E3D)`S67VuM9w!LiV16@HB7j6!7eAA?aA+n-pHrUXKiAO5PEShlxSr z=k0g~jC4wm46I0+w~ZF@2FKhc1qvtcqDk+-aWdXq{2zvvX}`cJ=9uc>7BpOdz#Y#{ zMN_XerD!C^Uge1J>+?RDmKgi%?kN*PnadGI>1eu)ezsk9pbb~sGo9UQlO|2@n{n}@ zV{I$rOK0DWY}2oKXWGm@zVbD1FClJRFn!RT73$>BmF}N!0!4&T+dpk|M1^p$Of6I9 z5bWDDL9bvPGlYCExFWv(aO%2ZmGrv+hT5Bc9z;I$|3}qVuvOJX>wg- zXcIlMOq1lVr06sm2Z-WlpOvs6DP{lS?caNhATJ!pY=WO?exEL&Z;LD`{vm~9(4;M* zsr|mj1_pWT!AoHJ1EE^D>e$@;5AWj~mJe&{+!}8AV|?{c&Vz+xL4P$&>o|59jN6jO zI-ioZOhYRRn`CSH%{V4|2B^`ONZ+Ok&TJvG%CiF9Kj(6#%fi3!yCaT8nElF#{SceH zyA5=3J_hO7OP$3tWKXneGQd|gGuF0<5tPzoc5asExWB7j1Z|9;4W*ESjj`CTn;#!B zv%K_Y4?UGp#sCEBO?_6>d%k5V9#x?H z^i}U!DK|HDG7MDDS@BzIUR+2u>zbaUn8(7P0RZZ|R*$X$t}mBWn+0-zapPE63c0>D z25c_NWi-v-UD;HiNa$IAOb0IF{3aJA6N(c3Tmy6d`zEHZ2WR}m@69QLc0!z&o2??H z3!xmv8p-(dn~EtU5VN{r2;j9UQu2^WQa8_5x~GN_`a`(^F4>Aj7m4*h7NTDQH@D#j z*R>DKS@2dZDCjUJK^p zy$xoOMc!ucaE0W6uoq$PXXR%6^rU@kScnd z059n~BuN1XS>Z#b~jSE4dPT9aGF6J`YvQ1H~$lEmE z+>k753mnY6+4^Zrx3#IO>e+{Z=?UfJ{F`YqfKAyi(JH|D(;N_+vjs|Xb(&+@`3IFU zh;eagZn&a&NGX3GI;=+KNYlzLFS5JS*;1OeYdEmFZ58au@Ftn_xi;rRrmF7lG?6EV z5|9ZgZ1ub)^8X3_#8M!I|BwXkG*faZ35OJ8Tu9BUd|!+k40{}k`g;O^eas^`cje)a ztr}s1i#R;cxVij}Q$Ig`|4tJRd8wRBLOPaToUA(rJKEA}O!qJn?Z2YOX1NUq49O*} zspVz>6R}H`m|cFAd)m9@m|ARy;y*qLD#qOLWBTk?Z2|*L^`|B4_XcM%3Cs8XkDFTv z$KLDbM?Pn=0#2!n>85Y#^k<_WSN!luY>)(}1L*5(cGVRApR6kL=&q#}vdaki(E($^ z7%1D0I(Qg3y~rGq55N!_YLtI+%8otyuY;bC4(dya-%J$vnDC#%ZnL}*rRevZx;jT$YkR3BB^w)LANrL7NluWri+ z#Cilf1RLJKpe8LvS^5v;!_)D&+uh9e=A+nR9XugBs?IYrUXpLDZ>~1&A<5g{uvt7= z7x)-24zy@9N)LW)_Z>1TE#gRTw{eACbMc^KADD`6&u1&I=l@Y{t!XrpPY}Zivfls2 z#Gdp0vW0OD+_$vVoO$+bv0o+ybD_%skDRNK=AA!flY)Zea+NPWR!yI6eQXL3StoNG zaF);hT-Xk{Y2!mDGRigb^gG)SxfLJdmygOIUsuR>yz@s`CYzEQtdb!HZUS|K@grg5Rm<+%oun|zYkk#2-X4to|@ zCZidq>e~XVwop}yB6=(s{`t^f>aPl2R@6R}Xh+`&c^tJ)0u4FcrvuDuMgUr9!|ogB z0(6irjaXsqZ%$CaZjvK!t7x~6Y>L;<+K{N~sd=X${C6F2c7MVr_b5QF*@B)oUB9@+ znYqm~-DXjS5b?(T>CIXbzRa&AZ64e7U9?0a(&Us}YZdkz(Q$N_(7*DqJiHR(T3cuy zHR|sjo{afVCZTYYCsV!YeB~XqB!I`ric4q7QM&W3%w{3>M=13fYRB%n<&HS{%4vpj$IO=f7r`c~Xfr=&a8mBOxE z?7Dx)4qD+^Am^vMMo0Rzxey)n)FNuERT{WsD z0!^{xGC(TD(eKT(c~*pXwhc9q5uaga_@6RruNt{3-DW#uoJ4y?!uov zo+(o7UZ=qZ2ZB2qyc-U7cwc;74wqI&tfU5YK+E^8xSIe{mQ`PHAZihrrD@%Gu}(W#%%Fk9M)~0 zo6O|R(gE840u%PNUs_6Rty8R246alhpc^fgzv{5|N0ro-RAlTXz6$Cv z`g`_Fw>FvfB*`taMSuRzYvx^+)(J=SjS$Z}vg5itza z8mjxvdGQfg!Ol|m&aa*gjMiKriLqS(bT_;FxQbFmEl6~x77>u4j7-t%QW41;A~68uBd_g5{vvvkNSw?C}-`_k-aoE zM&MXnbe1}VV29$up7S$0RPp%Aj5)Iv`C&^jb4$&{1nN0To?OIPm&DgLLxl}3h-F`s z6l7kBBB|ixe3qiN5B@rJ*s=HtO+T^bINbeZnTDC0zVz~(Y|0{vwSUwNUlDi<&Y~FM#0Zvkd(_4WA;=Z54E9e5pN3Ot$q0wh{bw z-B~&*cv%@DeuAAgA*QEWMl12myS`aPKjYwj76p2N=ThCicQ3ZA0{3f6E*}DfmX{yc zKAk|nF`C1S#Lc-Bj0Cu)jFB*&v5*c?X!Q*fJaI1@_JSvtd+Q!XF8+bOs`z1%iOLvU z=rEN=q3deWgq{#BoqcP*vL=mmo#?@|ANv40qm>d}ZfCkysLNqCxn zWv8$x7ZZmpI`UK$59vzOKLh{{0V?|2dVb5d^_(4h0$fBbznuR5;Xfd1gKyW*0QdKk zZTGLAkigYI-F-0Tm1^~j48uqiP-;*YU4nfdRJ%9t{lfm%f~dEa;k;^IwJ2ujmF}X0 zFzQA9pYN2qwj?!+a)Y}5EXI#;b2g60CKr2l=mIqOhOsYkCTp`{9nK*;HPbbijSXul z4n#a6Xtil;v?lA)yYlh1mi>wx+`z%{c@=11;vSq}hDPI?5P3%#_JOeaSmhg8BUd~~ zM{ABo?S-f8hPRJb21lLUNwW$44!Z6b^rJL4Ik3G8ffzr`* z;eI%Xv_q*O45sbMtPIB2TgjNJ&AwabhM{8`_%0RZhStLAT}FOW z$xZXNt83N@px5Bw+hfA%0_B>IKcc3R#`ywbu=d5Efcye(Qt65UT!gaSY^?d2f$2y^ zA93jk2JBvL(_v=H10@BZvz>O}A-=xT)d9r#-kF_NM_>Qq6pVfy4A zDs+K04Lom%mEHEfWLuo4Z|k!?a!rNm;o`5MdEBiKf&u>e0K0`e#e$o*6h|?c zxDx1C9SECxEgQMA7ZG%>OiK~GtFCKm?Oy@vZ@2Lbp#C&`@)$OvS>ZALl@-TS8D~%c z_1(#{XUA#e2O7<_@ zjof`&ut4JuU5I(ut~FIg?_D?XswLh<&KJ7P|8ehZt&j7A#!vmeec&BG;X6zy!`Ez( zr0E6OwX|J-ZMh)&OVqoD7sK)a3+gobWjGZdsJ?)gjYoaen!{kJ@t;-j;A~(ailhm8 zEI%Ge3+<8fS?>N@)*a!)>O7h+1}2~{SzWf{omvX^(dAIVF7g{=j??9+iVpchn{rZG zcEXU}s3GL(fm;vf*7YlU^%mw7Z9IIhJsK=SD*%6U&l0%HOvfmXUHH##bzADCTAoYo zxh=Nd@0iX%a9)$=n6318)Y8rgWS{wtUcX>-k3?7cL-n_fT($^c%B7JytRpxie9S4*JEb;JqF`zV4 z@ix*fM|jaMbJyN6Kn-GzuT`itU$VR`R4OigX)Mq!AWA1qv5_~L#JYjK)vYa{wpj7b z=#=RGv4c@;EI%yB=>dJzJy72vl|YRZ66v39hX)3-MK&0#>kJbb7wh$b2r)AHS3#!t zQKTv{7=U<5)jCjMMkeN6`J_yfp*f(u&R5jvCbP;ZE|UI*wc0yAK~=TzQ%6lm-@dPVV)#@X2Y-TK5_0HES!3533VA3 z_bK#W<_}6vjSE6OpA@TVm_d=YCq7+{=k2#7Yidi>02fJPE@VTH$+Ek#p2^d<8Wf)p z(#k_X;{P)d*N4=A3eMwC)%ISE?nRxdyin!m=2RrX5K1nYzHq>HgQNN?pmJ=%9kowK zhgeiusJp3+Lj`(gKcuClvDv;22g57IG+S!ge0y9Z{62)am9D&%q~KmG3u^uc7p-~q|R?Q#C}w3lXVIE}7uirO!cP+OM^TZO&3xHRQO zz27C#T}i)g$3xk|XAu1Q&Cv(+a2QQ>%`^Qk4Oo>d2gwymjMX@HNeVL^x?E9bF}WpEGCjINfA=36(tM?HA`gAaZ?#VG&P=5 zh)IcRh07wQx^)6=V3p4i$$g_1V|`O}GGRCi^3)Ozg?co15d$_Y512bB=p8JS)0x#t zZ=QPB)02a5u;r?azt`;(cc;^=J4N`5?Fkq~@s-*{Y2ZZ!OmOFjV9jx9urj8HH4p$?wN`}} zYnnJJ88aGlC_f44K%=OCjZ9#DQ+bGkx~mlI32twamX=gQL9X4}rSZdzHXW8WJAapW z-D{2%2K||!1i>nr-;B*fd_7x?r_hhpvs#Hn!dpcO{aa6H9GI^@mi;6mZnbEB<{&X( zwoLO(tZv{%NB>MrGV5tvC=_w{EBRYBL}Ql@*lVAtp8h34i&B>+CCs%i}{Z^JQfB%X%J zF>%wB0!cA^i2yubQJ!$hQYT;agQSYfz3D!xF_L2}UO#O(q@~--6Zg@a4PW5_;W!oA zQCUCAzjGH+;nVVc2Ht6(Fg7&qCx4*gc)huCm+Dd8YnnfRQE2v@asHsHx@XJ9Kk(OG zSI-P?a(Nb}AP0W`+hs-q3jUHXegUD)bo~zF4(<%YBsJ?}ZN+)#i44tA0I-Ugj9)=7 zL*bx24opDdY#jW3_*<5YGR}zmz(k-rB?8(pUuEp~vxq<0ck!PQqtRT*^CF}NyxI>F zG0L29v$${@$jpGTcm*Xo0jEDXr{XI26GkqHHfiTraWciV_ZC!UUZLNfw8gVvDO$sW z?r$=iG9R%nVH%@N*@xk4x0{xCs7gq$#f&{p4e)Zx(ssTkDqC_gNJB)=R9L4{?Yps~ z@2~(-HnzQCDzIND@Y#ow5XOm{)~-A00PpC8(=IwCC%m5+A8@Y(1!yr5>MV0P;|X`Z@uv*j6WG_D z-u*Y#&K|7OmLP^4rIjSb01z)j)L-xBZ_OBIUDdyG((`4T$EVit)*!k!?0tm?Piu2Z7?Li}+_!__riAjZwXVoWF;OWq zQFcWAN=DZ6`C4Tn%^GxTbCYCXAiM$Ot=i~qVFW*OhxPGX*CfA|x#sUE3b4#_J_+N7 zlI&*V)?>oXD6g%emH&~X7%Kqo^m%QZF0lAYZ~=96Nq?h@FJ`b9we~6 ze3tp=AVtT}nZMoLwDN8N9HcJGa-#X$R5n6_&mcXJF%Kg9pCFMuKqT3_L)glZ-bGx}NA5zjnn^#LabAB%HTHCi%T#MI|Y-fa8M9 zaqvQK7VBmksiVh}-uR)nDKQ|xLfFvZ7KE}~qu^8yuA}ymFfz`wL^9V?{4Ft?UWR|H z7rfmkDep@Wiux%3>pE`+Kdmm?0*0mc9qNoT2!c8nfScDI&-Z$J;qNvNr>^lmYCOg? z4(oQu4<0@w0OvIpTCB?=iw^ndsCXS_T_6ikzWE53I}x-#WMN^}z++W?WO1ztqx1t5 zI5W=`;@)fX&7+3Non!bF zI}&Sq3P3;Q#t&ysmd72JeyaOaZ(Z2aFRw!%reV}y0~vCoZMN6{*?3u$xpby+y>YC5 zcUI)Zw4e;Io?x&N6^^*!bJ>@S8}w%#X^eA>|GdCWjoZzJUGd=Wrosc3GC2_G@%+Go zQ9diAN57RROEK^TBDTLVbUi&^vQ&`lBl?IMIW(2-x`mi{ggcFR(Z-)p%l_T>o>Ya7 zGvH!yzTQ>QWjJq^MT5YwR=+0InP;F1cm&6>eTV+i$G4&aZb>&oalaE7*{2e$54Xge zd;J_aA=}k19?xXKK%?gPy*f}b)h>{HRwuwgy80Bqr>kl6FYU``V%k3L6(Qo3kwy-v zNd$d)fYj&$?=o5j{g|69tK)usprwn>oIz9?I~LkJCp8^yuxeo@>*&;RgE`~`&Iow` zq5aW>rlONZ?o$LqE$MlDg8d37?sJ97R#)Dec2$g_1K)UuhcsR+pP z=0C9RPONJkbVA$o<50kxJ|*dj{;J0o$wc@BODV0qR}Re8&{%|j-Umj)U}7IOCJxeI zfH`>XSlQiHIx;mx)*mzRRhWudj&g5NFdLs3N`UO)h1saJAKKcEl24XCx=b%t1&-q! z?I^SNk7|=w=Hjss2R000n0g8I8ua!^C1Lc6!|v%dnMW(-B?Bm-;mN)%e*T!I?e(hQ z3lCO&IV=|K4)+4kv86d0qIvq%BW`FI_qEKa;d(KU2@95bn&p-4XeUo}Z$)R~LY@mG z*1$VVaxT!;frL;Y%a0xJbV)d8nD_?-xfq}cuAW5Yle(r_G3zhVFYMaCjP$N+aHf2P9;D&Xl^}EBq7Q)ENmIfUEVDGxn zai;UhgAoPq4rP!S+D~8Ko2~n3Y-gXz4{0m1(T}%?*BaBmWCgV zu1mei-$M1fr-FG6ppsy+5*bXug&Dqpa3{fF*s87?5|P$a<7iX^Wo_`rYn9bB#`sD6 zSCXc|B9hah^-&z_C<6<#un}HjA$B)~-K7MwMZ+q^vy6mVurpeB0)*xMxR*4fhoSJy$aYvVl%W*iwU(~ARpN$fQF571#!ZR5;Fjf1- z#^;ORa#e!$g~6qp#{MDuez+7@(Y^u_*CeN_sV{Vgn?2(sBpc6+f=VWLL@5#Pq256Y zd>>u9#6(FUT<*z5G{C*NfsQ3_`S1bo0#LntJG>s4{qBC}nK*Sa(3dd`=pVfDPffs+ zK3sf-?mZ5CBQk=w<>H!H&Zt5+dk3sh(w*ro1^wTuHDptA09>oLR&ElN>hjj~F*t;& zJPtu;x-RwUx_m)CQrT7LuA9d0d^AU?rFBP>?1Nv~mbiaW1-1NI_#pwTf##n?EO{OZ z)*BjaZnNhuv5;@l??b0C+FLd9KxpWH{H;}Wd9v#6bgj+`C_Ta>A~xjq*@?rH-{UoH zLJoZD;hL=H83`Ys42Gin8w?<#QNs%&p*l?_4!nyS`XP#RNw-0I?008cENDHXvZ2Uo zA4Ft2GOuE(7Pr1sn~!I^!&5%3xYo=Sf zeX+ZJxA%;Msy6ws$dOx}4LA}C*gKqMgj0tNqmNNu5JDJ6V*sFI_k;~ZgY z_6bDLQVM9e@3d^8WMwe>w@+^YtG+{NI<0J@oltad4fkP9dHSfP6D~nvH=r}MlI4U z$XdRLBl%6B;Y*KZ*SDitl7GESZzg0@Ko(`kLU{drtqg}^DQ~eCXAi(L!_bxmM%EZ# zpN=P#!H#-|EfQ)9gFrL|1`!~o$n8F_lhH(Aa;lrDq0-1JKVBK2ePF{4)Yum>v$&)p z8RL2(8`WM-RgNuLqYgL}U|Zp@76&9gQk%2XDbc~Jcknx_Oz#R>H3KxsF@ z6u6WUZBR``9%Ip^Hm&mQw1HlimIu1}G?nL@iZlT9a(hm*ricoiA51&p)um_^ur5}I zUTP}|meZ<;1B~wH62wLU#(<61v9}O)MFw2VONrCj&}b{N*1sJdf=yW%u7$$(rDqzd{MRj;Zcud>~dC+Og}tS($HAH~DW zyBaOQ>BUVvxG_9Yhj#-X!vS&-u=fU@VeEgqt@?K3q;N#5rsnm>SwUn`o4D%g9q<0P zVX%Feqe(102~6rx@y0OB7_H;+`mj8oy&LRt{Wf#wWP&ph05#%6)Dq4X>a(#nu%XBm zD!AV<%~cuZv%xp`G7=~%Hh2eNu^cFxvQDlj$T$3mEG%TPNsJ2obVwxINGWTWG!7X~ zz&QgjJ05%V1wqa94f~i&gj;Lb8$zI2noTP1njkfzH6maFY&bhB?ykqBUZ*pc{}D&h zE+GGfzIUz1Y<2yMa(;VVhBQQ5N)uw+HP-7e)|(yI(A(NR8(b5mh%k_)E&bojC?YER z>5Jj$M>w}P&i6!y-pm)A3}$cBA@6|e3#{hMVut(-a3SbF^z$k3TYo?C=GmpY_5&09 zzpSR}kwCnPOpMo!#e$GT4#eR|lw0qYP;0}U0fUL}tHH(stiuH#;ZMVVcw(WyVk*8? z#=fJlg1n_n{>H8wp$>MK)PA=@BAmlWyL(BnX&<|_iFn@pH2d{z5^bGM;?-GeEew`L zl$jfDV=xC^h09TPZ9C4I;&-+)p{T)^OLL*T%fe}c9M(z&b-x*+?MDbD ziSPtT4#H0Kflhr#{Y{2gnPy!z;1(>uJ#W@xbxfU?%H4AKBr(TTIDBYDk~Xxs62TI` zGv%)S4xV1Ik1D*fp8meKu`W&mH*!S=AyUh+EDWp*H))Sufg)A5l8%^U_=-zeEvn<( z2(B3V*xKuYApjDc)^9HEOF}T@L`SBAh!g$+t5JhN=wO`2o@2V6WF@#|Dh~}`xBf9b z3H=v7?4ev_Ey<1|`GiHqM$NtpxM1CQ3?(BRssDC?|C=#sPw*Qh7jD_ABL1ZD-t=9N zk0O$3*KkSCxoKA%%Jy>ix0IV#0JJiPmA2Sf>F}^egJ&U56$;T2mM$YEU4I=$5zZHw z888-Nb-6JeX0}^zgwkj2gRG`reh(SV)=~zpzyqQJOPj=`R#gfw+Qri~J{EQ|su|Qk z`qodM0nOibICFPmdVx|Vj!+mtTdVFc*#7gC9r3P#Hmcsv$@(>Zi*t|T(Jt~A{GUTWDsGth||H35* z%t=<|b>Eq=S~OIJrbS3=+*1!fbxqGb=FiYj2JApzKbVvP;{=~_#+UtTs;-0Uvrqox zKWe1}d%6?1MxM<%^V}m}0MIw(&Mr;+PYV+gPW~3QhA))A*@b4w6z{Vs(|^MV9Hw5b!B>$#0OV_Bg9BV1VJ0_7`viXr zA?UJOm?;DalE;oPZkwC~2GVQg!Bd})>4SW9GTH~Zrb zvCudW7|8#}`a(K5yD92lh+xGiu_LKcED{lAuG?N&dp+0`~lMk5*d^$4ybj?^mXhN0t&M z0imOK1)0 zTWJ@ZDq_Dia^NW6sQtaz=gHS3PCL8P`8w_nr!0H2F35_B7;1y)Au<}aHlk!NFuty; zNU@no?gVOP`I1cef7|qSKJAh+r%p)t*Rqy(d+~PE3q!+y)*w1l0d03ARP#^5mh-+>I zemdqGyyoK&Wt;h=ZE~1_)1Uw;g|7J2q^w z;=ga^vaev-iso}W`}Whv9!C%_E74 zx{;May!>F@q8gsS#HQ%O%^0kMh8!fhOFFNw8ZpEnkufJa>JHJ>*i|M@K{x$|1*4)N z$7tQ9&3OGB`0=3mK0+0>3p`GAF3^f#AWz-l7;*LcN@V=fhX2B^e;}asRWw>ncvXjP zduqQ08Od7)=Cn`hOT+WtxY?~a6u-r%SLM#F7?>Jo0o?WEG5GH!Fgn*LaNiuafvr44 zQ-ybt{?zo^NBU24&pLTAQ0%CGcXmiE6_1gD+bBZ3J;s~-Zy9=Q4R@)dW{Wt$-uyrs zuXqU7uwjall(zGc5K+5-1)9*|JL}wOx#lHn;e4V&_JF>H$EdY3Z39Qi@w%@wD)I?w z2~Gj@;}D42<9ZRP*(ub88rfB)D=T-VX&i2ZkAi@(CA{ukMExGP6BUm6 z^clKnlNFk;4Clcc?IAF#?$B=b{mGuzA%WQ!u15IP8g%(o_@e;e_uJ%kPkn zH}8sS>(P^&Sx7Tm!A%*RrUgIt0`L*O|y z*vw?df|3aygGyNj+eCDc&+wZDlyUCDAe?3qon3*I8eqBE6I7O#ZCvP`yv7qJa?G}} zJgG*NlGZP>lQrBU(9g?Qp3PXi=EKR@%)Sx~1^ zjv3;yqSXlwxxrNjpEJvaTN=tp11Fu$)jLi@54Q^_U@s?Ekhx~%;rtjw=g@1$aM-K? zA$2j!4N|8`zZR;?%H3p_pJLiVDVV_=_$)Mskt7wQpf3bGRNI$t)u2*-RQ@dIEyTOq zIs;Hab0!r$6?1m=fPHB$WSmP#O5l)!c=lZFg4A2PrB=gWHF?xjS0VD)x1WHAYGT~S zF&$@<GW?kd?yp~maI4mLH+kD^t9-`qK`9Zh@9_<~ zrrY{C}<{Qi$Wr#;+TTodc#Jt03>(y%&_&FAmI&*P2x$T-7QZbNya(;}Y9t4cY zE~VlWfptn$p@@sdL5qa*>GNKt_}YK4po5)}CnGKf2^c6kt3)w%Z=g}O^dBvnFpL%! z2Ih6YMQhc>{a?+17UB`C(A>iO%8(QSa`ozpLb@eAU@Fr3*Nh}(K6oW>% z!|F_V(}h|pZopqNedP0tl)^p_p<--QwX26nx@9|y*FQ`mM|i{ae*z@(dFc^*PLRBH zM-*c}iF@O&k#_uV4&yW^ePKUK=)_QfAiSFm0(pd;;OVis6GOnz-vus!JLBR*GNJQY zC!WTn6SAH40l?tG9tWV`m!Hz8(to1X?<%MYF#|UU~lZ$jD!Co+*_!94luy^OMx1LInI+!r#z6)o_IxFpu} z=Bx!VP;~1%U9Lj8_e{=yXTbps_6Bn}2F^Jr0&cKDWM73~#(YZ)+7H z4}k~d0oc}o>@)H)##M73_`G?L?AP1$g&IFCu(?zJ2Bh5JGyEqItH0M37ztUzPk?pB z+L*uoBEs>XZoixu?>j60QCfjE)4r#`_lcLp>f(s9b=_E{tL_Oulh9m6Eh1Nrh0j3X zBZ9;jS9j_4yG0-CN=|44#IKyNnQPWF0gsc`wD&->5>r0O5FgyKh^AHuycmWe6e;yb zExt`{;Qksi4Zn@_h0s{3s5swHO*FkBcFTsC#3MKiqpqq7g=u;GSy@>JLR>p?&_O4jgR`*%Gx9VQ0zXqeH{!0Sove~p}Bu87bWfj zR&mQN0`nciUhgLN6=6|l4~~$zWC~pJa@3KMdyKhNQHe(fOuyX9p-A+lKHA?8dy_!S zhNg`ISJ3|RM+18wAu+EQ_hkE1mdynrYeRldW==%ZE)S~&xE}xG7tVG={ONLS(QQu1?s-BC zb5D;K41Iu@$(V=#X+x2MBIc1)qUZX<%Vp!=C(213OjXu%CTIJcDe`bLr` zmwF}NxuwgAabVrhZ)*w{QTvYtmS-j4Sr_Rnnq(s&=T>Grrb$Q|9`l)jxZfRU;?R0$ zaFardY|KVmIl)sU4HAO2PhTs~x_EhBvZ5L=rgCY`Iq>~<*z=)rdq%m{sC-hLVJ6X= zIoLL5`k~zZPp#eA2*=#^*Pqj;eT1pFf70+-S|xtr8)MbzZ-Xe(&+!wxOoAe6N?EM4 z^$z}Us{wrZaXYN|EnL-C33g12t50*4K2QZKwuzhm2DWC_W-&{r%N^#MQhw+F89|_V z!%V*P`F*}{#dlnNF-Ju{{effE-dgoU+f^Cyh6 z#~?JeqJ4>Q@VHQLuuUB|V2ym2v-jQI3>Ui$8USdIi6|qZdKY`A`%NmFzR%u5$Dud} zL%?bl@$yTIYcOEkH2Ix0|45D3VmW&t$6>U_s$os9J0hH|)Pn_QQ389;C{)vOz5~@? zSpRDxL&o23A{1L(AQyOqoLy}D+-Bg7`>MG|D6>cf{mj^AnXPA+ zf==urZzC6Z#r$KIUle3nVOJc7m7t^72DX3hkbb~uS;YXfxEn8n5Id_+x3d-VA5}@D zuz}nGuke}=D@RleEtMcyCTo$t+|*fKZrug?@vqd>MqQ%kS?|9D&Bhy;Zf_+u2z^Haa^gxZl0?SQW;Uw|Ax{IxxOi0Rhd3Z014 z6qOF|4?Mwn$H`_NaOhoIt`{6;KK>nNCNaAWi77+44t)|z;`@zs1Wg6GfMMOJ$@Y1q zoes=n5-LVZiWaF15U}cCGHkBDNQv}wypJoE>0P#%y^YX zeU=YN0fKqEIv;+D*LhL-?zF}`b8!9CmZ-}EjPF?Q z7*J1j$aM-)AW-NDk?XZT-GSm^07{4;~faV@RfQ;Qt0l6?N(^yKY zhFakdZoQ1grsg|?6|0wbuv?d7@}S6<1*LYZo|iz4B~{8LK%dz4S7 z>O$jrSg~edSHrf{YNJ4i%Y?7jakDj1Z7NrlSz))5A-9MwEuS&ar|pQEwM`%d`WdvM z*9wnk)Xw?zim>c}cm{qw>f54R<~xNd)@@T%K88UNulvC<3H@OBfdM(pzZdb@m(ft1 zXij(lD3i#>wg#2MGMaI)8UWsGq1+QacxImNHAGd#QHN)KdX?%~0b;u8xBJisAUUnG zHC7@$Rc4ZYGqxkmSidF)rlp^H;{ljFH81lldy>e?R2rXrcL3p?z`uHq`A6%oEt1#C z+9Kr46F+ybp`2wPSnroDEI87U$$;BdKsu<5X%qESp8f|OQm`&Ir>420`v7WDBxtr; zLDVS|1v4h2YzILKKi-!CQ(pN!ryUZ2@rxT3%e5gg1mts*Fp%5M7AseC>+A`Pk zeh5OVyz1llkoVB^956iAHz`X@o^zkF?2#nuT@w#aR-+=@zU~&O%F}%L3P5TVjyB4KZv|v40bK5fVX=%3t~A3E0+?yO$zUQY+$5BI>EbT<7EnoiDof z2P|2t6mK;wsKrB^AqLklSqTeKg0L{xdjCJ^%<0#2U-|3FJQT06_n+W?+>_<3rNT;e zUek&iW8w=N#=PV^S~7Q<1VIJ0E1+V>SA-@G1^!cN#J2P&ZZ9^NB%2j3t}fS{#?;$K z0E(?MI?+uL>(*5>PWV0iu(?Uh^)edSavqZdm(UqYJ zuTEsvIM=LM9Ubo|wt$V^Qwr#QzGPe?8NV=pCleO~cOA2VA>>2Q>v1sTc_Y#T?mfsENJtZ=bD4=9KsG0o>b0Qg_ zL2^$GKg3Ni*RUQoj^+#93EwPznDBnPFl0Omm5I%KjVQy@r6})tj1^|>uHgFC(`WID zKZ9id;xG{t)&0>yK4FVHABkzFkJVP(9lb+V{WEaRW7B?NR1bGnBGUuT^e^@+c%gS1 zKMY0#i<$sD41kqYj=RMYC+WRTY0f z<$aKOB^>A?*PDvj5CGg7$xbFqKT-zN#w+v-v6kVUcnxd;Ino19@%ciZ3pN4mbH=0` zq5FL(AoPDvN^I+Vy;;^Yx7|XmN)1l=4$|exW&5iLLtt%tV2#K>;QXBOJpt*BUxydl zLL6Kpc1}y2trVn3*pt5&j!%25P9%N(td0W?8BS>`_iUp`?VQd_JL(GNr3RFnpQY&E z)9}fHFVfaMtDQbu&vEYRaAbjpriz=^b5O%go|0DLlxdZ-oU*;p99ZyjeyJBS2&4ey z9^U|QtRqXdIi)@uTtZs`2)@WDg+Q2MciI5cFtP!=RPZSvuZUP2TGH711V*0Z$u6a;dkB*vWw+irJqWvBr z`|OOcAT}TqG86NT&D_;(^duU*EXcRHKkPqY3ny}d!~^Ux5|NvMxCb^6;8TaA)% z7z586<3F*xDc9dncNQ*@fh!x37iS((#!KUae~F?!*rAO+7d-j>`Woibc?c%cIp?PR z++RC02c&8R-YQ!5)~tisXXSt1!8q{m%kD-4TN~a>;X3E41h0LM$zw| zU@X7YvC5It3VPgd|lh~i)RMDCgif) z@>y@t5v0p(p;P)GU7U>Al4U}T2C)Huu;Mb4yaPnAbGHFaRY_HC-YGIT3*-g8t^ly! zc*3H|dw1Yp$T4O5GZ=MMcp?^Z1%Me6s3(==zk()oAZ3Obg!T?#2_9fLJq|er3{Ow5 z{0eiS9~M_`teyZK`II*8T?d<+cRi#VT#pBeiMhpwV=shxJgAUmni>tciMY`biwlq| z?Fq}R@e5;d*~uON_z|qqH_?J9v;pz?e$y(B@&iS?I1w(A>uN|F2aakf;n{cXk-Nfc zs%8*L-HITT7HuHz6{**8kndo5#4AktwB1E13b_T9VWyYXvHmgvf+E( ztTErX_Zx-ne1q{8vlQf;8d65z7HCKw>GhV1x@OxRCX09a{+qq-BuCpfdi8=dL#9>< zmQrty00Fm2o7`P+Qj>^$Bevyee=nl*>W>skI$%GX81B`qO0o2JOlXxbU)@D7`lrv7 zKi^i5e!p4id`W?ZM4rOcSPn8Y3MF8G5}J`ag-dJ}0FiD$#eeyT;V3TvBXeR;;e2l6 zvvcZ9MkI<+!u(!ywhZSYnHc81-kSshfN`M7aFgeJ6Y20)<*BY0&2ub81bmz? ziw#2`!a2$}9Zoui>-1P93qGo&J*ZqOGXmgb5%*%#I(|q={EuRw`~AaTFjfK!n>6Yf6Q>_7)cd+WfgyFBuIIY~Z6?4~ZhKB5GNw%d=b8Es-TXPLlX&w8ReavWQ z)%vIQ6AvJL4Qvvz`Y#zb#Nz~o&-&!luib>CzLZeE6}nQ`uy8hd7dPqrUJm~=Qd4tn z)o+U?8>32qFP;x&P2xA7;yog!Iw(NagBQSMN#Ntl()kbj2nP`H|Qu$ zN9VyF((l0jtiURJX3R&^FKyDov$u?x5y1i`<177rSHnQDxr&<)2;(~#q$KBkOclvD zdK*Q0as)K^t&v$ezp&HC7Ls8|KkY zLtRhXd3=`cE{^8K;-;#dN)Kpv^8{97VH%wqJ}^Dtd{t7@=`} z7g*_?|A(hk?ob2?`~J&2RAFR&y#j0XMhjXWIauuWYP><$L5Y1x-2Hc8rpXT#KT;2 zB4l_tb<107lNbnYGSFeV+Wn?VpC%2+9%1G{MX*B9T+pnY6CM`~g7n>201S0wWTiE( z3HJXiwl$4-e|ww^kM209=y0{z8gPr*zf1__)x2mBZ{<&GGnWOgmVi3VccwZsqiO_E z8p|J{V8SY;8PmOuPII(l|GCWM=46JE0K;0pF^q1yNT9MNBb2BO8^te`F;s^I67x45 zNEvm|(?J&vV)e8)<_Y*d5`=|0(N;9&%lqs3c-0 zpb$b(+6IDJ=m%C;cl&MgdKmu%shfQ}Of!pvbU{C0tpX+Mlt8?cleG%!)onH?HvD?l zNEsIqKj@#GxexeKvTSjl{-i0iqR!V&iri98nsKl=RAi<-D`CD5V(5$5PwM{UU{kdz zJeH&w&Hn~_mGtYg%dRD?%OxZ2m_Y@@ zF~fx0yqD{kRSaxnc-q()7nAA8GVYNn*ehnr6LPh|DY26R&9vy2xmo*|+RS9*h#|4; zdpJ;KoV-&L2GMffE3!<_zE6*+H$6VP5D}1UETUJxl~Zsp_kH_9YAi{r5|F8M7LND} zjSLxiR(vl|D|>yD%=K8<~DkayQEJ-)h^V1&BmZ+y1XA;zDxam-5&ZO-$+x#b1hUBq=@2HS$kU2zvC+ z`WD-2+mG3Z-8x1onETvlYs5mYs2$treDo=cwd0n|uO!E$Md)t^`V1Ooz<#H?Pa3}m zz7yd*zQ)nFh_w9_wL7VR1UtZfb_1}Vx!Tzq|Toq$2tq5ewN5{|KfIrV0ZwU-MqWMKO!0d}XSU0#B}WK!93 zw4<>Pb#migHYgK~^7TC-j3;+RPDe1${@wK{?hII_E8;YIY~{FmlAdLG5kimpV`Y9 zI!SfV@P08d$1_ouaKK_nk2}81Y?m9p8WMlNZbJYTDTORJDpNVpP*9cT87~E#*N4I6 z4@(v6N}A|s^XtO&?gjP~cj;3Bg5rs6BYo7Axz8)UV#q6*Q(MGb zcSfc?_o5K1h@ruY2-Yt}+s!KB#^<+|5pEN>EaY7n;>ifdA?(>kU0_zpK<7PAARa52 z$hJuLxjwrNLJ~QHUPFFzPs_4#Qp4yqn@Kk!*yTOQL?n5bak$fQbVHamQ95ux2#f_m zq>G1~f2THOVOjp3yO)R@GUq&Y=EM?{lq4D`m-0}PIheGk^Az z71FyO^lN3H4udMzp-aMb%7E8lhr^VM4SZnm0r57N1#cB|R&Doqj-0_|tD~@KyRRuc z5@`j|k~BQ;fy}}FPLY$3xhpf1sRNz1T2L7Ji-Fp-n*MU*p=ue;8G0ER{iRGjthCHM z{X?Vdw$W$hMF&5L0W4@Z3{#kU8>_M!7aGlpZq8!p?--aRkalTa75+#p!i1;%_MPsg zDJ#q*g9GeJRBYU#j4VB-wk>S?P7qAuX>wNkTR*V9ww#mncjMnC>YNeyJ9j7)^_rG2 zT9zlez)t+qB2MCp<~L`8Qmx{$MMEIq=e1s2I+5JD`OA@#0VCx`9u2LV?zb~9DBLbc zv&bh0Lbo~(vD5}5b*{*&C8TI?Ros+2B%Dz-68^Sfh<1V8{Pr;TKR&O&$k!9a$iV;^ z0UFKojk3KiTd1PXy#%H*wN8=sSB2X3y_K7CfRi&=3hY_zy$&tYQ1cO4`x{F|1`F0i z;{hFV^L{t`t5P+ED0i$Ejy3x*b8ma*x31MMK1yiqE)0!zra4_zZf{f%KtnB(eK_&? zXdgsIARs`&7xLr&xy1~9>VMFvJUfdUVe5dm9wG4xyhM{^ z4Z88K4pV+7Pry|k_mDn6BRF0@FgTC1M zD!h4DLqIPAyt<1O=)d7Q<-h>~(J?|^jP`GlbYUe8iG-gsG&(lrN7{1xkdt$ldQ z((l5BgMRdk=NuxrQZ`ATx71>11E>ZCzzD*JI#EvtD1V4S)$R=#MoKZ>hbQ>@fYiVU zFn=bhl3zX*bVnTE?yhI9_4oOI>9hYWecat4$SaThC{eNra)tsWC;PJ!GnOaZ!NTD& zEoottGc=~BeYeBa#U1Jg5k35(#)|k^EcPPWANf6&bbVe1cIf>|J z+mcstn*rC3IQ)$`59c}HMk$}!hb>pR_*O}`7StI z1NJ6ICEPkp>NQw|8Tq@guc*NVVwG`iDqT{Oz#<>bH=8*VB76#l?j|k_jr;M7CRk#LiN6fBJZQPhvXC}J@{n3%SvHD%5 zC?LR;eiF^=dm3UPwVyDk+)xYc*ruF#7TZ%n6c3bht2t37zPiB*Pz9CM?xjVK%)%e! zH%xDaz;^3D*msQBW(5Z!<>lecSPijSxRPDp6pW*c%pGy+t&r;#u-B*(g(=Ay)rJ(g z|BbT;=;w2kdy%tXxoAmKa8V|{xgw1?WW6l^C{};Zjc&kb_*FA6!y49b%wt`@$K7j& zWLJ7)+FYTnS}!c)n}okVQn0$S2pZRCKo}}gHw|G?!aN&k>026HpZ)qs%_sq4QR#OoY=At*IeZ8w1NoNOb^ z_Z4GT^W17BvD@UZ5jhcyJvR7Dve#q?QlAalIJ5i|Li@WRJuMl>{bp^eCJV{8s|e?b zXpA7S=mzZh`czb*Yc6f5n#-!TGr~!5#Sr3Ih~e{f zZkfZjmnvL83&xkW>m_qz3nyK`gkTwg_%hOR2>mv(JTjRRVeM-|k;TIyBV}rd_;0(8 zASRqVNa7EM!|ow58oHZAZ{j}D{OarbxK%_jFuPf>@1UTtgdYWzN{w5zr&m%&81bKb zFlh>StQSdpd^6k$_?OgICdE=0TEXLu$M&-<^2kGFvh8)bnJ0?St|*3me~26(o&tJL zs74w1rRC_MZ{G3F5_Dd1V+;ImNC+$BW*D~|jU$py0& z2}}}L)rZNS^$wgE6FV+jiQG91tn9ZfHu(Lr;=S$bmq0s0Uy17r^TcW+4OpWiL=W^w zB3(+Rzdk3hZ&%;$y=XFOV|H~W5{D?-f*s>+#}n>L{fSzlgmqIJ4|Z}n&zNWhuXKZy zbh`H&DVsX{Dv2`Hpf9KS^R!Ua>+}4AlJD>4w)M})=g__UTn5>ody%0ucer@aMr8=Z zOG&x$i#awysMX(};>yViK;v(-7G~^1amshR=?1i$^X{P(Bos6GZP1~BJ@OwR6>(oX z)PV9r)V1t~Kz1IDP~_dVQ`5nka|ZgTU7Q&WZIKK|yG(lE@l2=vMrEYTM9#A)z&C*J zaS3QV_bsUZEJeixD!{ok-wbVZQXE6lin4G$fLW}~YWVj&E+P!sRDuTjN80beBB~h$ zte0A>avihkAwrR)Bmd1a3~LJ}nW|m^N&NKQJNcNtO>OehsbJJ`pd({hRoQZoMSXf) zxjU8>7raQo6$pG}49%9i0&oQT+=56E1rRWq6B`s5e2ci!-|b8|mBCKZYKOvtI-t-u zUYWl8>Zy_r=evG>AB)fBf~HG(&>D9d_TUp2aKXhuNrY`Do`RoU&ciyepRT zXw;y;wm!6b`|d;VnSZSowifZ<#_~U2R&}WCfIA|di!-*6WU57eGSKMmDHnU*2W8oky;!lt=@6+_UWV(ura47Dq6gB% zD$QKG#{nfy^Yz9gWB1`cH+mZ%t5RUiu75B;wG8-mrw8SV*h6r$?1;`kPKtD^NRw;4 zV>g`>Eb%<7VjRH|oP(oVDDyAXBmzS1pi-!dHUOr9D+{zS)Hlt0hhp+O`ZW zRHZa#L9g4u-kc2==&YrxY1cmmth|octOjn_?p#~`n1ctAm?2u9F}2#%piY6_mK>xv zIlLenvJ+RFX77B@&R{FLyd1}-iLQ_Dud~FA`iNj7%dtcBDuMh%!o#UsyOQvq&f1DUHQ%Tu|_I<4M@L1{d-o2 z9Vq@r(Q*`6V-4S;wae#@o?2ccICwmlO-uRqbKZ`(CZx9}XSip*y3R0$oIKM5`Pk=_ zBG7WT2FX)KAt2yZa!Zl2-$PzLd{X8+w-VXBn;O5-wVO}YjIg#_3eIk$ya%ERCY?{C zh`h@GI(m6+e=S7ROvIm`L>@I$fIOuM#sC%(aD9nd ze_F`&L{k|n;J^D1z(j&<3N{5>xEq;DLNTO+5KH8Oni81WM-h2d>Q>!$5je zmGiD_U;Kgdxe0j3ZNM?nXxaqf>gbd?$x^lL9jg>5f=G5N3LHbQ1T25|UQC4Inc7(l zotb0!mq0eNxe&D{?5aD09o^4?fL~Kjjuhoqg%q^-xAyS8CsMyV?^kgzHLG_ou^XeZ zGuHN;k;AxPY>$vbY0-QN%}%uIq?aW_Ci>m=82-JMsCV@=lESEZ&!{0(+2LY`5INRf z;+y`PGFr?B_0H8L@mp;Vl{!@t1#4+JM=w5 zpG!3O$092xzq4o!8&x*8r(%=T8oj^R9_=^59By|tRn^FDLx;>k26J}^W!Gz8^V7zH zmlhvo1skHW8M#A<(=^@CG~v(Ja()@fYx+88sBWPXINokUi65<(cUbg!^k)9hzS@7H6e_-!`HDX`ElIA~m@*uap zaSw|Qbh3!K5ZYXanzv?gjf~)!lq>2Wg5=_x0^*Rta#0fu@CwJEpI&kk-hn(q2->vK(-XXKh-M7o3!J0NB}zsU9b%9)HMUd(*m&cql3 zQcbL_gJ0+|Io}XG(kNmrE|)+{@G%^ZXDV`G9=RX4+2nFUqW5+p-Us%vy=N@)elTFQ zk3KT6g$V4}-~i9PL#gsxHRMQ3BTYFTh%)+T`E6vl;Y4$^zlyc`LuP5b;xj^~l;2;@qhh$i_uReOT&r`I^q+W}~d z-xn!*B2p*7e)gBbBL{d)2p=fWzojjY7n9p9aPRM3I;D@R;J%oyx7l54$K6{t88=J} zoyolSH%?L`*K}Ov8)6X+S$ycYU7%fq-LgW5_TKj1`mo^ODIPJ~ObSaO{a2mvQ#erd z!sNq_$=H;6ghCa_u z_t&%$9#TNK4l`Inp;KTvAm*oVBmrh}c7%Uk2o1DQwaVNX$=g1II_yRLi)VW-Bl&l~ z9t}zEfAGxUp#dC~!2N4?h@15M+>!iz&Mz?bw|4H9U%ad)45pdM>eV~b($ah78?R{& zGlQHamBHAuYvS}48kyWWciO!b?JfU(khkiHMG*}WQ(!1TXIkIS*rWCkSG4s|ENpiyP_}CCdMT4W$1~PN zm5x9xl@PzEWT<8hW+}Q4gFUITJn0in^(nF+@XabNkH>L>94LtSaz&X?;{LC{Fb?~^ zOv~?BLDI^=?e59t5$5Nslpm&^-L7Szgye9tP*<>SsgY9lqrfjlluf|wnl?gw2r+y% z+?NdOlsGY-G&m;3oyMn2KSlIBZF(4vk^-<1x&y`M{faofsj37vHy`Lh-LDb2dfhp> zm!8^|7hzA{ygS5IT-So9df6DW5zgTH>^GN14J)0_*r)5DYdUzB6bWO&{mV?Hv|P+Xt}^4o$04PW_fh+ne3B{7#$g?|@;w z9wBNv^RVNySav-1ce{%|3)<>+Ylhec-Va!pW$a{(-pb;Y2Z~R2CGOFFonSi+t*AIm zuHHf^_B1Nt`ao>g5NJCgol3Ml@~G}{5;4YG0wN`$Q9UjviP5xLUKZz`R;=4J7|uCN zF(nTa6RbZf18;2(Y5wFzR@NKe%h7RY{5RE}j2D=MmVyBBF6u z(4+wT4+2f~?Zu%Teh0r)eeq2yqc{x$L;EBz+5D={MEzcjRaNr@g54p&hTtc9xYbUN z6RK>;LfNxCRHhW=Ape#?<)&Z}Q!9(l!9cockiOrwx(<5JIDm|Id*dS64FLrha$R)}JomY9o6XU;oe=%3;dOH5mTkPH1-f5x(D;x%*`tZM zV6&nVSBO*g&)&E82$xUyrw@i?_rW$3?4V8|l-Kaq2bLQ64*(H^v?)AI(Bq%#oiewQ zCi~Q?Ot@T&+N@a8VhXNgGjr0M9U0%BT45Z)k-&naR%XNVNq!onoyyg2d{x80SvE%|4bZ=8KOdUeXS+J!dty z;5yAlW!$z!HqVcli+@_XnK<#PjL^4yY&MSeh8nzTLGA(u%Gd)Sjici{|4rTMVgl1* zr;s!8)WDoNVVJJ;=Z;!u;d0NzEK!)ik+FSNVh0&ZxFU2W8bm?l$!KHtdH6YT*~#j0u)_xgVVIDodJrt zsB&jxOxmRd7+XBh;}W&Q6OL>CU=f8vYnUb1nMrl-NaF(5b~0BsYw?V8xbV1zxe);; zX{I!MIn5y??;68D&ff)=JS)TF+*hP91G|;voSKl=w}?fu^tX@}`|${B&~RuEeyaI` zJYx}=5xGa|XbJOAldyhr?dff_K@(SsWa5Xf&)}Bb*isIiMy}?alQ{Ej&#zy|tcsWO zNbI1_;-_vlI`0q13)Ak3MOMHuh*+jtdX3AUAuBE^+Jyft4`p1M^1tr?lLdxYlH1WwyN1m}AYExDbI}m1~-F zQaQzzb)X7|Ad{X*rtK#Mf+fLG-egH_kuujh!&r-Ei9+X@4wEp_C~e^!XJ|$k%K;RqaH}dT)`d^0t?8-Zm8DQU>~&Ct+RCZ zN3^$=r_e&Qy={$@K59P}*)DTVEo@?6kx%>zMSSE>J)>_9fnhkptI`1kQU0U5vO?|C z$%&8Q8#EC0(RTcW+_=bnuN>y=@br~2poa^c-R$6h9Z(u=)?x=*XK#oUwjJd&;mzia*ic4O2u&Aiq_dSKc7 zN414$uA4vhBNqbP7}p65{GZgp6kw^6X~ziYN-p$u1Q8pg#PJkD00Ey(>&L>-*Up)q zf$|*yj4UxkkCr1`J*3r*tuKFV!I{xHA^<@EHex`CN8J`3O#vO@sXA};SlBdW0d5lT8+rlL8x1!>`W3RgM9U`r{>hH+Yj37-~yXA<_1lH$(4k; zINCphqMZ)apaQp#>DY)hqQ8?956M2)aI{n1cqQt1N4e9Dr}8pzgj~jO5Uv;M#O~A& zzCYmM6Dpz=5d=rlcI(~4n#&2!IcMImY8=2~9Qmz7n;N=Zb(VGGw8?pdn59?8?NWXt zx_l$F54*2+e~phS z7qqrYFO|sJ3Hgy56{uYQ zsY|MA`Dp>W65hjgK55gx1ePS;9O{rJCb6+PK zN`&6`YCjb`wU)WD?JJqelU#bP<(l5{xZf;(=}FK6C~CqA?s zQ_$I0|H+vMlAlC{3KE|TCH0+ud`e<#MFA#rFo`7&e!sP3)Q__Yew{1b(McyCB+pLc ze{9q}$*)lrwFSZp^un=Mbk~F5aSGJ@@qc2Bnrk%3(*g_pa?e@y1U1*#J)(^Mdqhx) z{%Ltpt+7I@Q+M~JD0DhK2m^m_ktEPi>lTn}VK&~>ZyN)}z6-2@af=H=gvLb{oBP;( zSO^ZcpW31onu$n}HhOtVBeUGN*I!WKEZ}AZS8SO=^)Z`&phscdyMc!3WYT6C=VjE;=eF~BR$qV-$BXLKDoek!eygJ5D5&DW0ey~J0a>wBO95@EN^9JN z6ScSdE-IvWh zpvvbs*RGk2!Y3+hP5Q5+WEa5N~#r`begHT?t@U8`?pzTIQy{{^MB(119G{T;$x6!9K`} zfcGONGJqFE-!%^GzQTt`)4lVvA)LK~m_XIvS{n%q?r|#Lgi#Y*?O*AMY)Qp8=v*s& zA%t!#bRn}g!gq!jn8o9gkOE1_`9J3_t%gH@5$tqaHf+E-FLN`rb_Ao+5>jk`HpGUVwPP#;QAPO&Qh{2v@5(p z*tiyoWFPG+%EGi(+hpN&>ADs?<7F|^N&(JJPY^_TYcKzU6mcRrkJIQrDnvDF>e7fW zCPF%uogWi?i6x~jqFqEt{bQ5Wl2UQUbRvSnwp)5-CtF_Lg39+%_UX*gwI_C6n&`dG z2Z5sgs~BsK{K5JISW!tsaT_M=9k%Est6$yvWXcWeXM9)zkC7j33qJ3KBBcS zuXns@T^`3(Qz>i@9A!T&$9p(ATFjhz%CNRE)~_jJlg_Fj)wOVl+OoYlrCLy5I;p@} zOopzqbX(pi2|1dN1E)*~qH_a}KxJVj@7xcFC>XXpoeCBvhlaemsw1y=z^?;F4bVH($(IAs}I(9L~eos8v#?@3`)C{flW!tR|2`c z0_xO=NSt&?!4MJg5+tEnmLts_gUZnj)CY23uQd$H(H3O7^=&lMz=LAODk}^9V3_)EP$zJnmLI0dH5cuK{O<`XB2otjziLoR8Zdis|bl!2VM4aphh-e{fu3W~T0+Lw~zPNMd{j#{DNCsvEnKWguMet%87syh!(BpyQSM z_U^T=T`6>$<7i`1%=E418DEPkTIwbv>gj-g!#ygR<iw#00v`+ ze*|+O1F5E38+{BEANBQdyYnocd%Km)g%Z@fJ|w+AIizl)QXdma^XAZU#Nr8?`6leF zKE(A4BTHGAD(yjiawYnVjkvL}4{kECA>mXaC?Z@Dk;srvwN)nkTlbDg|ee z`5!C$3vx1%1zB4?gSMEXHngU0`-3geu}m}jNH6-1h!oAkb^A!7%s^8mYFFSjM&L6> zkdiUJF=afaa??-w&0=A7eLV4iyhXw~JJHR%qvOxye9P#YbF+qJL$PMI+4E(06Z@A6 zO*T>cKF!@&d9e>gcF`;C`7}{njC8%-FXeV-j>Kd%G&sXR6+jp(Jd2fMV_FWAff1@| z%;~ZrIN~U7P88pp>2(PKggwm-xKKr13n~)mA=UK-E;~BW6!}SmZxKiO0|Fk}Ln7qn zMKYUK>FPeh&iq+frYDWfF2p%*jA|5dPP6SZ$n#gWDgX|oH$~xbehSR6zZ=>qG1>{5 z<#j5KE;ur8&9f_Sc~)!Cvc?F0x1~qmAXsop_5z*zX^F=RuQ*TQH%M|S8uLpw&Q|GDY;#$ z#J@a&DQ>U7MCh*4oWH^W_W2)dEI8uZml@e^Qu7jUp1%#9vP_UFj5PR|&>)H67xB@o z;< zlyj1k9}z6z+o^V#1&#j4BMM<)H`2s-SgOK{{MKf@pO(x>n1|s2(Z2iyyxtUH=5b~r zB>`rj3{?Hnb@@7)wlxM*28RhnyDY21`u#1G6TRQ;G@nUj4@%Kd9OnQE^YbN9pS*-# z&58#Brx6D{QdH;^YR2PGOIrV9;CPMM`|MAnj7ozm((Q#ZAH+U@K$M)8gHIGfKR=er zL&?cJ#YSk!LaKwAKu}2?O7K>xC~2}+JMuyVvI(6A5ez^RM{L#t?INK8@*$Cdu}mm( zo%i!esEp#Z$FcpZe%;dz(L`bqCAmg#*h~6kiBS_qfW*&K{B6F{c}dB|3n1L53;)y$ z5w|OEfXnP^-#mL?Y2rqGj(!mGN5A22On6C8XtcOMq%iq1T>L0iAp9i}Ux|8!nn~aQ z&_K1-_H6SR3>-s|km@tZ2mXw!TRnV#BypFb%kdch3r@RCj&2Ne%c9b5U z_!f9*cFC8}&!F?Zm$Mw-X083lX+u<9L-a@YJi3Kk#a|4ORF<+UVQ1Qylgg(vFwdSE zqz6wnQ!Nl32A$td#eIWti_ZrPccZ-LY?eLxCFf6b}CO{KV&e zYAEp~T^&FN$uXBnO-n?sGTO!l=|BVe%^jp}A|4-!HRRYM(q5lJ;ySY_JhyRbb%reT zXi}jZE(*f0O$u~llgE9>zG*f|@;L5{zjDFlZdE=R(JN#o5cdUfy!<~U!ehZWNFCEW z;Vjl`A%0D;E_|S?nx_r21;aGmMf5EIV=n)kUXrdZwMkfYToG( zqE>gnoDmO$u1>(W0&m&mXXM#LqJ1W8V%tE|8!Z8S{za5=Zvp#xNmaZ zdlXNaBe3^sFi}MyH!E^5IJg;D;477Qzwyk-vEDygX;IGLIWq zua%xuAGHD<(C1Y;g$1yi?hK^fKfk|Lm&}oFjb}QE&pf}NdpZqRwckAQ zp1b%sKC(rEYN8IlwAiq^7+Sb1Ei;CR{jpuL2}jV6509;Q%a>f_V7{!lbi{d5j-yEY zjEuZp`U$LmFxfGdtM8B+m6%)Od5qMnWvh67sL4?F5otH8l@moD@TdN=z#=C4_uyB? zj||ny$fo#I{vyF}SoN})n(7}OlKOYzBlVz=4WYmV)i#n7QlU^UCdnA!mH+UGN)NkQ z{o9i9^2suJ(r!7udf{EGUOMVPyg4i8{4nS~=Ny~2@}eFWbxOuBr{g*n{3!Uo@pNx| z!ZE)Df2Yk*?B2Y-c;w{AX!y8v2Yqe0%T{ya2h>|R#fsXxZ#lfS2EVB$%6Xs@Mn0u( z*YPMzef-1$uw?Mbb+i2mn5JVBlN}DGKcRPoZJ-0I>=&9j7|(3F8#CAuxCM}`$)8dk;-RCMNF@J-?FPi)G$@hfm6aY2L4xcIPG+~pto%?2! zd7Qh>C+4orR_b7FuNdVjvKchgDKdtCQxY@AV2dM2wIL43)r`ofSsrt*4fPHe^?%^8 zl}b7tXSznR=&QQI*ER~^E!+j!#U_P7X$E%Nq2DW$0)bFFqdNa|7s~c;gAE=c!W;^e zb|Rg;{JhZJQg*j0J;+0C{`TnM$muWo)XZuo^18ETzjdapIvIf+-gEP#Y=+mZot>GRNs z|M%AD01(qu`4K0}WP3?2IkGAIY31+_16Y)tBN|c(5FT!`7D~~uc3a-8oQ>j&yKNsw zmpZ2(WGnYmP&xuEtcUrUnB#B?JF zKi%=fXKA$|@pKli@w+l%2_@}GC4ImbL;CEX! zBe$8Y^Z5|(E_1)8Zk(P9i+$u1-aiE(_lecEey{s$S_p6VnO%Zid=ZXWd_A4EzkHqb za-s&eP?1nmtok)Nhem;Ui9drJ1Ot$!VJg7{joDxZ!t?vc{9NRtP5h+5I6~}%NY62( zoyijGXAfb$0+2&JTMj-dtOMT&qx5TCy3OXm0Mw|rPnC>JrzMJ!BCl|8IWDTzOOb>N zE3V;r^IFRIN)UPjk*(-Jv2XzDq}!h2mGQ0#UAV4Xq~jy=?#hA^k>(v|F47r2)48j0 zO#f2rTaR7+!%-@Ml!w2($^v#H&%wd3b)@1vdB=UM&#^HQlWX~37v^9bRjJlrdRcmR%Z8WboGP5YZ{~~GgR3%rw*woo0c|Z4N z{OSF$xlyOl>4mh0-_b#v#W1q5L2OT-(nj-mB6Pqtb|Z}Tu8j9q?i6UV&ERfdZ{+?C zjjO5M=ex2=7CNw-a>mZENiaFxwDv7Iaxc=eMfOA8sHeQ;d>i*e);N2+myWonY^kJ7 z#EKmM#h;5EZF{*-IvfXRy(ke$@@rSYm3EkrTK`kg(TeI2I{H|`Uh(%zL~8H1YZ=4A zRliMt7Ph58)t!z*Lu4XjxH|y_2Pir5onrlSF@=N@$szrO=4+&dMHvr)&)dB68{CMKQ`3fFk zJ~8J84aad?ytU$KP8AET%r6;M-GKJjWa3bX(N(QOWdkH0Ww;bkJ0a`-{^G?(}H zWKm4?^-HpiTf$v?d6s?&S59Abic?r5k0lBA_1h3myqzi*48`!N2;$btQ<}HzjdDtZ z`hV7mv$tU4^SUNc92nLkkcR8d<>0GCyXOc zwNe~&?tzwE*N;e}O_A4lT%&rrwTZy`;rphxa$OUo6_b-T^O2K*ttH#~DtEA#1-^-z zv+UL&rdts)qoML8m&f<;o3TTS`R~7MoUcUA=>!cK6b`CiXH#4TY_ygVY=uscu7TNHz920Us; z+rf3^Jn>j@seoS0SiV(_98gt0!sqCrhj%RhAsnSU{y9=|hQ8F=AFWs0RQ|eDqw(2% zgw@E2@4o2dPLJq6mm%b)gmw`qI7f-}*QetE(l)8?8i#y65Fkq#!Pk# z5i!}@AD><9t=a|-xj&(5#)Y3qf1ylNE-f4_Dl z3Cjd%qQ~0vh?Li(Zy^!a*yr#8v@3C?)T?bxstp}S69a%FvRZL#!{pV+B*I%Jd~}gV z-kG?@He2Q68USrS+`2T{1`f1+Nz(G2H(60XV_o8V@@$eq?>#<3fQrT5fmhw?H={RA zfuHDc$RRszZCC<7XC#$>Bx29Q!MD9bb~wKo7I$j@dZ?O%I7)p`*7`C73jarg{8DrV zq-TTmfPBpe!H;luffblJNh6r)CY?HqJy*%Z862K>ZW(3q*M_5>+{|Mjy|qSgz49LL zu^|-^JKZn|r}JVNIx`29O9%4y$-lj1(?VESH2fO5Gy2SG z3l41VCndBhI(kd0G!dp!l=)iPJVR!K1$bVZ+W!%k1w#qYkreJ`+vJhmg7S>g7ljOcfsCJTeUkL08=T39$#iuSsLeYk{}K|cF$$u>e4&b1 z;H$uB96W5!9FJ;2pU5o?;Nqalph-i^UQV%Xgh^ge313uxNWfG z*j)F+yQJ`{F!^xahB&38_DZ*5C!SVzL9Q2{+>7-p7V@>&$}Q>hO}OJ0hyPWn(E zb+-DPq$}l*x(zx6;C-^Lg1qPFt~((ye#svEGtW-njV33p+M839S8B4YQog^(TwwRF zNc@OfG9k9xQNLDYN~W|dIydKV;ZsQU{3L|*26#4|UO{WkzdqAd!1&|2y{-Oq!E_~N zRql0miojo>@(j1w>1a+nx8%|^&j>$%@CkMv*%-&4f7`R*)i9CHB@c??EiAhYBi?0) z@&L|Du$EYDBK2PlN z)t*XT%<)m<#*AHAK>&;$AU814LkfkG->hY*6+QDAldG9i>hjOsRL-WwZ|m~_j*NxE zQ0-=t^%K;+RCjje$}i(}j5-(Epm)r&ZXLg$e{41NVD5oKv+ZuFVItH7o$&k9`_*?R zm0v0Xf5)m+N@!FB*}++w;g!0vrI{fI#G1o5lRLR7%wsl1C0lTcoi_V6vBqu?ul-n; znieS^VSd2?d_3xlq9P>EqvYRwi(|JdJ8ZFcA2_nO%HbqnrTZHPtQ@y-hW$wJ5 z2^s?pB*U71?N9`!NibF;kZCzxkgD1lI>Sa8$J5n8Gu`_3_Tc8>=Cp;{klwkv^5rEt zHPFUyhzq$<+o@;T_0z5Y;7gAfHZy;6oW_nm41={jb*7_LKMu0xX7P+_T<@jra50O# zFT1j}(wp^NV8p@LS1ef3H5{$1$kqX3BLPnV)gur1k=wMS+TAHskpP^2x0RT22nWnA&av_op{ z;%I!uNVam;lL?$bE72qgdH_HH1XSo|cT5|<8h!m^_-Uo-=*~@IKdee>X1oUyCWd4b zkA>VRoS z%co944M*e7m3IUFY~mt@B3_fdHY<<#&riE{ceEc7C7?DrISM>Q znjwWp9so-Q`BsCzI=%o5{iCLcZwK;m(|mBfK-X2x(S|lSa;Y^3y?Pf3gxWdByVS#b zWD9QU`=ZK*h_fG_;jThcP9b~jdktr8!AB-xK-g&VEPgG^1v~!8CroV4Ot)sth)sjA z&(~G*v|^H-?X6iv73?gX5koR{qyODlYDj4=Ho&L)+fZft;HD{4(wrGNTAcz@O=%rq zBA?`uPCd~M(0k%O2D)ZOQXt;xtJe% q|^F$aD4uSd{MFXHvi`6o2 zD4*_*?VT_mSHS&bToGjCQKEUogQC%d$!sGeG_8FTOB&_Jm!joB0-IQZxxo&k{+Tq6 z=V+Ok0GPPh+Q~0{#4j(Zl5>%;f+R{sd+{T=v#V1J=(8!A@tT|RV#qyuSz{bpOYk$e zpPw`_DHMv%EP=Yi%P*?fj_JLo)bWQa&V_oS2F^(~#dnb^2k`emhu^_gq17N;;Jiyu zB&QaT4?bgylLN;@+9~p~v0<@pyJ{T5QOgZv+sWYATRFJUs+rG41KMb-8v);xvJ ztm6Oi^p1gbb#2#n?4+^T*mh$zb{gBZ?FNl)HMVWrRvR|9lW*m^pZEKjf7yHOIoF9X zj=>e7F=aP?8pdZuILll*l6-;i*jqZ4V!ht{-s0Io$#`5tw@jZ)NMV#uw_J1&aF(FJ zfm(@bU`(4j$Wg~vuKx6?uP~wzcw9Id@Zte034P}?Mj%L#AR>4t%*<9i7tqd)GWeATH<+cj;qc%`4X-L5vi1kh~=2efP@vy^V-kt1Bz1Gf`KdQe(Sc5FNpihwJn^^b2Hg(ZZF!|^tl5%db|@KRhe3S2dE}-nNre{ps^mkKU6>r6 zA}B_{e3;Kr{x{6{MbAu9j9LB$NKYj_GlhFL)9m(5c?8T@m7&*WWtLO|1(iotJ7=F~ z=A2|1e=+|_7Ff&ACKV#L3kv#6EJ=ak`Y63)KS$LVREmr zd)xR(9I>Ol`mWts)f-5xUu3Bk8N3|1?*`v&(BnB}%hbo*;Kiw&@l znRrVVdgLRI4NNm24l(L8%egz@k7-0yzRM3k7O&)z_N8!Vo_e>fuP|U|?s;6(>r5}k zPFEbR-Gy*3k$#`J$4V3I+-%OCnzo%^^mORvZdd2YiMM_+>%2y`_!@%<%@&bX+#5N} zrEuNfa>Z{pnNAc+&mu&)jB4>1T=D(W!gLu-=O7u*Kokk9X<=%YjTJ*@1KMI)o>C1?K$PD6f1>ooUPuJMJ9Ix|_CscAl}D(oN>|KQBUOXnKrfdE!{0nIgV#U=Q|wt-w%gX-|0RL{ z&LYjOAE>5B8=(@kJR#6tp@RPegncLJ>4&aD*nL_gQt5l33MX4Q#j!xh&xD%@agWqG zPy6q!U*f-2%_C(rNiK69tu^UT@2(NjsChN**Boojb1<*)zM7ge=m(yckYCv;GEo@I zB=YlYQyLgKLj$~zs|83PCy1g`AJtB7Qba#n2If)$t4YQ7n~~eV-Fz%zTi?d1g{8Zn zBoUTbN>oj2)9CG2Q~+Ocu+zPfzvv3z*Mx97asYvujOFuwcc zd5L-6%nsP|@4KkmiV0>K)1J33=?yoRhqF<$2C2evm$&->2e^0_%{L4je^$VpvyCV8 z-xp3%Ib5KweKrE0-)D&Vl+M<+_fumi-y%J$Jcw8zw0DXBI;><(0vO+v*c7KxRfzl1 zK0qZ{i2#3sG=6(UiQ6U-7j+GpF`f>IkI@4!7I^5E=`c{-rPAX?)0tGrS&GXX1;qi>qf{ahx0+qV?ic~-US>49})F@5) zlyW?5x_tLCo8CJL`_zZt$d;$QMkOO>9#wu`482cKU7X#V%Xszs^!?4gKd;}1{9KP{ z&7&^5$lTl_2U?Mt7n6+27y)s{H{Qp^Dm~Pbn-5*dAhhajSxIZ%Oj?cX?OLC0u<`?K zY6^G8Z%!zG_k>B_{ zpg_e*Zr(-_9tfAwFt1*>?JHLF5C^#X751>Ef7r$lw-eAZLard9FV%aTmIvISM*^9h zYz%lYv0Sh^SP({iYPeGw7V+C!4=HYZL_kiW=VFj^ZX(GqRjF0NLRPswd_jVffL6i2 z$ckP^VoUa9t#1?4E3!rjl(!N*+pHNK^&K8NFhBvYB6l0{IV(KtP>(sIapDAUs#dk35R}pDlpyCPDU+BB{qtML2^5(I!S^hd@qNgVLwi6V@H;cPU+fDfO0M|$UMxCtP2VQ=^8vu& zFxBD^Ig%ERSiUtx(WJ&M>j`=le#c77#SSS0aq#+HTlF!M@R|P}kH1O;8ISLYsB2uO zhPzum>Il1s@#R)tH3u%n)*mS4%>iXFm=(L8o0aZa`a?>WY8@sIf=T5&o2^Z3lM+C~ ztvaJtr79E#1`%58FsKn*C7*H+5{}&7{?6GQ7cf|8c_`~qgU72U|9^^LkgNEI%5|FX z#khY3bug-&!+z=Sfb%Uq;d3^#o@wx8vHdD0?zJtY^qg8sNa@*ES{bY=Gls=m$hvV#Z-aeN8}+mmW`iS_&0*JZ zO{+-q9L*oCMr5&00M`)+{#>Gl9KJ?1f#m%U_=Efmg~;-{g=@^zzs-Vw8ek|70adLP zO)zch8OjGZtoKKS&(Kt^Yt4C0zb9Xe5sgea^P6O7s=YH@%OHYIt{HcHsDr<>3ZF{E zY7oExX^=+ue3L&krh3#7L8wgBs+RF81$~U8f|&0YO1?lwdjKxNi09Yus-E1Ul1!{M zpJI^yWQcY0&7jnz-;I^=`g^_h+Mq3-EiuRB6zWCE0YU<7fN-5=1b~p{;^D$dXzTxQ zeT2(nQ7iweTDL_Z9Y$l|+2m6f0|Slnm+$9ktM+4%3Pya+tR^|r2g~OXxsSCHEY;3h zC;~_Jmu>g2P6-ww|Dvab)WbGT)KCMMk+o;OU|CY;qCOs%2^OBX?SlmyWl`2tV%)cD z@6m;Ouh`1LfbdeG^!`CbVT+Ij+3Cfy1Alr;=HqRS)cB`eT;It#3-T`ZDOjK5dh5X4 z0W>dtmY}LW63~bskzxSVBOJ8+>E5(gkHV~|*Qb=AmU0tDTUeiK|B;cZh{#n-z%by= zb7^pFI_y>WPfSa^Q$0LvQmqn^UpaC2^AikN1QYOb#9|Kg&3F5h)gQTOkNSsr*kL{G zQx5)lAdx?cX-_ux035rSbVTe~_KQNgjKECvNAQU25zOu;7A3D=pwD*rTf~zM>I()F z1HM-_e+;9o%qj4G-^nhEh)0}h_1BQC1@KoSo$lu&XkM}nn>MAXi&W=n5r2w2j*OaC z>E_c!x@WwNew^aHWX}^Afh4=z_oWI;FvG@{!C9o@cXwelh_6v6 z7iL+`y`-itHmB_WIi}NEmGDB@1PfK3I791@`&_b%Oy@d;Eo*K6`tf(0<=ZK1Z#6g6 z1_S5lnE(2dOa2Y_I4ACO4jkCm%58bT`3>Paf+YphVurFR((^}q^!gR{9=Hdv+_Vl; zJRFxfd+RBqPM)_$N?P1LDy@hG%YU^7vm?wv+42!H+*D{Z&QZl0h2gH{#foWSx5fk(YM4>Pr?tO zR?X$?wF}p-$wlkQ7u0FKLL*=yyUzOZ2I=YYz23Z{uWh6gFkM9q5i0Ur?Y{)T53BzcH=NdhcZy;gskZeZ(*u!n(jv}g(i31xYBc-BbViF|$Rj=v--@?? z^OyBQ09S&XF{uirX8|w^5^;fnhPuN^lGORbBgkIa*XF{Q=yL|jYlNHpISvX^s7wwP ztMjFNa}Ds{PqTd#?^c4|_tBme82wgY_oZ_uc}x!J$xoI^cQ%2OP+8l0nvb2TU9u-kJVsq5hiqj-~1B!Und zH?nc-c}_+>0>+$h#1p^jgVDceI_s??oI~u`d&wGU`cX#YJW*Gmj0N;OKx40fEKY-^ zXN^1rU?9frhCdGs_-vYo;kS{T&Oe-ae^l3&%1@sdUarm^ujnW7TwCD!fJ$X)2EfSS zYWj+gQ`IO)ZQmq9wnE`}zGe=E2)&({JaLMaWxR*O4~+#YNY380Z1CUNn56HI)-@S= z-d4i}`FIBKx98F}Vf6mDivtrq#j^x&O_D6$pFd&cyRci7U!xgipI&R1`C)|!Vx8DX zsnb1Q(aF1VM{gy+6u_xxJ$LM#L|-2Uw^)Ed01xSH9%U$N0L30@aFfcQ6^yZ2W^;o4 zq^J&bwj~+%X}4dFRcLLDYF@FU~bk^)D?$vj7LkCVM95H1oK?WQowx2cTJOQUbP9K-}pip=P%3JGEsx z!qL9G5f*K*{U1uDmp|3Guf4dU>+b2xn&Bo8^Q=~i`*4(XBre;aRSnFbRa|vlL|lOC-eE&e;Atq!Ck?vw zxNI|dpQR+1oyN4$V1lF6DdpQr!c-{36|gUldc`SAj?0;KgtW;^AX7p;XjI+wdBwGu z2*Hn{^Qsrco$J_+r(8D*c2BI#Ls}DPcbLZRkG%nib1rb?J zoNw&M7nDmcP#jP^fN1;`K=e0sw5)lGG5AY~iBCMe1?#}*1~qxK=~iS~xccQRJ*2xc z0IgwT@2f)@M=GER=YZIB25-($n{=5q_~6leW{xuw(Nha9KVC%m|A7dbs&Kf&Zawct z5=Y_vfJU=gmr^z(nkoNi^Rwk54TX~QHn5ZQh7RpE$y@>V%bu%W)@9iqd}Yo`6CBv= z_$@o{OtJ~ZH(yahf*+YD{PNqvu4JZmZ=;|l7B@pbDlv(0!7}tE0?$hwyA2IpUvEG8 z3gH?1(kZ>&1nfVyVQ*fG00v{QloC-={oJ{45hM9q?}~>B+*Ic`FWtol98Z#KgPNg` zwPYw@fayS@Du=HY868Hsd7{TWDfz%za@4eXCQ z`>9(DRM)xs`ZFe^N0sAHD^JNn`i!zpT2gB-@f(};sNk6oJhM-k2iusmiuLUC*N8Uw zKiWh%^%)tbhTIb)v$h={qqNNNeOLLGB@lDNhF6GQEI;(H;|})5tN|MalhV`2+D+}k zHOQwC{Z8d;sdF8&gPV4A0;F*zTPaq#-FSn+acCs?7vObSy%6Y;o1TYN_RlTD>$kiR z>la_)y&o|&a;(=NOUH zn3=o&wPKI%QHk7vLikY8k?sa4ONsm{e|m?eFld($^niQ%=({@W={jDpHe6RQ`(J8V zY;GqT)+pF(11<&$X#$0od3l*c?us+^XIAkLaH?VpH1?AvUzstNo?RoJEDE_~%JQ&h zSom;aKzp!{ADgN1KXw$#PoXK|V|tUC0$0m*k~ye#BnUsrV)Q5T9TJ)R878grxV*ZK z{(XTG5Rt2Eg5AE%te=L$ZKW7wuP>en73YAego@1pc55jh_$wwBeg<*hGNU#)+*+_3 z^_a*m_OKD7g4%i8Uhd3#lVb`!OK(;2pQ{tTPOD6$|!I`3^~~-11vYIs-0dd zvF5>lWAX|#TquSZ2UW^B4wsaXapqNWSOzwidVgh=anqg{*Y5%-xB~FX+b{bucRaHJ zZHCD=AwKc!_K&-i*REcZF18H5;p#4KSCu_U@H3N6uMSN*E$?|;US-1e9 zdzn!W{1EoUU(7(%2?jeF1s9FoBT~ALgINDaRsmnU459lzBETw7@N=P;H|8HlSFHO3 zdV;KitzqB(f`&IYGVn=U)JGR+*OCajkll-8y0j{B`GC;zw{qi7?O^kPBJ@;Ma8?J} zq#K%1v&b;x#h#PXP(V*po(Zl79;sUa923EvT2*kYrY;kFcco2dKb>#?VhOYUyaws^ zB9&!WF53|UGS86&fDSV9Vsz#Hj(G1a;x7C2Q~{&MWc;Po{gf8(B(y40tH&KMC~dY{ z*7A@nmslx&8Vf?nk3`-_u$CQ;(yN#yX(x{-U$iVG?QV>pZ8~*U+Eu|Y?cs1m9bDW5c8NX<=gpD#U2f^8%gX4@C>P@?gDQ!{E2t-t#x8tx zud$4Yx%M$M#)*tF+}l!K1mq0X^$ncgoI16Z@r?2vUd0&h@#;ZW`?r;c{?ez;IsRND&gaSqJr-md_p-n%YJcA5e0cU;W5FHVZu{S z>TyLn9oGAtojcIoFau zG;2P#>}=W2RE+wd9&PelGkYgEHQlA7vo~OZnlBg%+1ueah=xD@iYCg~x@o$krP#$J zP4}q^$tC|~yieG+=LyL6$*UYIH9X-qQ-N7uVA#b$?YvA>(s9{{e^hwRJU;P#Me^?y zOy+NUkP4-bJ?V*y|8;OmU^mWc+w9@7&_Rv-mQP`iI5w?NkQbl#Tr4tPBG}(8sQ~!M zZ5G^D4M#9P`K8;+IZUvN-`qsW$EG~X&Nm8&ke)o#xrQ;e;rhPlVV}IHSEu{iShabA z8pfIR%L4A7ktflxIA|u^VMOsYkf>N~FmD32WBgE1rQWZZzh!Vxae&fcNfea@Zm=af zMQBu%g_@RrPoR6A)0kC$x~p>THyuN`CGV7y^HK7vqGADha#gRVmmlptVafwdUTuIs{Ut z!qx$sZk<#YBVoK|Cubm_eCaBeoWAMj@U*J|wzm)EmGrzMb(PX}r{kZ9Pn;KE1>0yJ zia@I}CpG`bo`;41QuuB8PQPZ#6E{=Wq&Qv?Iane&k<*`F%};0#*J2WK6rytBKT)m&@lKoP&ZG|vgl`P31=ST}$2k5~}6Zk1x z+osdk>O;Q*w**6i-7G9y1|}u19@e_%pe7>#@go0(c$xT{4%a(h2N z{_>jI3K`uK#w_KrP$vKft=P zeDmDr&-=2?0(Z*xrCI{@;DiioaZt_a(w9pwfxMAWwk4(Zmyvvz7-i389O21p>&i{# zaVR%xMbLw{{IUeSDD*FFs}2dQJojnDME7Z8w()6;;hKogRa(pgnH;~1H>PoALuEDF zm>UkMqo&C=8vF#7D3iJozm0w}P{tjAFN!iK8g!BHbmO<{J{PD@H04`Wj~iEp`n-7N z=07i${p)if1>|6!FQSZ}?#1uZlu#93g~RCWMD+a~gr5H*1PO_xEfH?FrcIya@Bp!{ z_fdbDj$^sghol<7>d6RxkEasaBK&@Oe82K@D(5IWxsn|dde7f5+)PFP>b-z_g!KHo zXrW9j&PdS3srN)z@e|EB4qZ9uHRR`P&N$&{#R5_S=I+YbUt!Z4pB<~ zxBvNyBkae2><&!`RstkblX zq@^?YTjKtvcq|Z%LU3`x0=!$DuZe6s`oDqzip;bgB{>%6bGWcc##mFt{I6HHxdw=l zDu(D$_0ouHYFLkZQVn6@KruYWn15t=6)uiPbq!f^hF@OB>KY8-C}JKs0XmJ)*l&T@ z3pIq8;;FYL-^Ac|8Bbs!tLvCTXMpt;^gQbPc^K;j+3?r%66y^)~+fd$=%0(F>c59C6DRYvSErWMOQ zf3n+rpq`;%%{&0Q)frnoW|W$_vp)?V_wk_gCIsf}G}nMILrDSHDZSiL$eZRji47ey z@*q%d=aVKsLwnZTG^{Mr@LX$&f8bY?M^?SKo2lFlpoL0JAxDU-8z(;M|4*CYv(eW^ z8Yiad3=;|!qa#1>lKJk*DW4D^mf9*tb6z?_i~ta-5+nUC^eI9mDDa%aNZB{x0%90|-PR+I_Y9!!CZxOP#jwhin%2fcs(=i+Zt?WrBFZ3C z2cwHcBCHy;jn~R`>6_$VcARvz61!XDz63QY+qEp1{ZEDR7>U4DoWI3YoC@I2U+#JY z*0N*HMY1aZ5WO@2qTl%RFC9!nVcW?oQI-27*v_I1wKD=wlYyg2CQzf&8D@Io=R=+x ztHakq97I`#&B1GGog5v?C&PO84WnAn60y-ryl6g4iNu9`1g2BGB+Y(a0L>vrrsSdg z>~^oHMH2_u%=BX?@C=w=Vum({MJpN#^|t(8m+i3hGQaqlMTeL1W$XF)P0{Jl6I$VE zZo2_IxW$X+d6nt%WXYu79IF`uA*SQKhQ$T;Gb70`hyY|7SPjB397tFVB&%-(q z^qI2|!%XT00`JK9ufR-fF;x3fDoNfX^y610`2N&uGXmJlM1(B@7@i9eOP+}Nf`17t zP9O$xg)@m|U&JMrrD);z$flu?E9@7e?d6@mgN`C#ql2PN-h%(FJZ4q%bEqp+pF@hn zTF6izGpb=>CB3($)`U5{pi&D&MHX8M3;s^@&9xTghk#rHkX};p}2IEapL)iocS6=w&c%s=E6o>K}q@& zC7LjIO!lb8g+*Fq=^XPQY$g{lEtt*pu(@up40nMwV*^1A!Sz~czwn1 zM)4+YkgRM>Gf^^tl!yAwaBeo`O1q|4jj#Qqdj^ zDnhDcz2f_!tlaP({kL&$?F$YRrZ^4o{{x7$yj2T1Xm4ma;A@wxby|HKu^np;i_T-N z>Wf$FJme!BvTW-!Pd=qmhDD9LRIj#a;~!rWU`+5~4)gf=`)nVXKTi$iaoRdZ=GPut z##e%)p7z$+EI4E6i(zZOoPY+eeNSMF^Gi!2+2m8dj!+q+@`|W z4sVYWFnjh1kbN4@sFIQ^_VF2m%G~hEJJ&g=cU5y2X9kbrfx zWaFoJ_$vnRCUZ9cIb);H6*P=#3iSXjwDuJ+s2;hWZOtoJc6l=wi~d<7uV1q`V{490 z$A(T)QD|*bYIPWAWghL{XmUY8Vdg{t*{252AuQl(Q1eUk%Vyv4UsMRP_lxkDTuM1z6R7r(;pTyc_Q1=32u6Z zJ|e!v7OIz8r&~^&?J2vaaoIYSl5mf#Bk$4dvllR89WL>@w)fC?0LE^2^qj=84DiFCqxwLm1ea>wR zRzEsXlF0-tpD&m+XeaNbKOX+T$!+&MbK(ag2lnDhxhk0`z)J<1D(&c;VQsPCDNhPc zFrSe96wk~Vj*9y!so~SD!H_+5bf7}NJ9YLd7iV*?EpRqlJQ9i66v55KJ|Af~l;>uB z7YKf2inv@UsfwfjB2yq&qtC9cX>X?3I8F8zS`*#VYyHTv!75Jc_v+_jW zE{^c(n$5>w$%;Z?BdusZh?KQa7s>T#+I*r#)}cZ6`k$SC`zB4}N7q^MC620YA)Rrvx$rTuzB=tl+o~qHXFw_(C z4O@M&c@fpuS;xBy*D$SeNO~f9*awj`*@H*N+$FgT$Cn zi$pa?bpG0SF~d79{xAZFXRF|&P~^}%KNCWB`GMvhk=BWaj^otd?$2}r4f|{Qw+T!h zcj$!7NM2XzI(egoUEbqoPydHcx(R#UgD$x)^A;=bk_XuO8m9qAuRSLg`!%|lMnv{> zXVsk~v5cTPOq>U1GLex<%0AOA5~{L|5H^sr1S>wKYYN5jD`!4-9D5YF1QE>-UQtrk z0l_qRYCznY-D|6`@p9B!NzRxN?($nTQUoK2Awhx1?_7JkH748%jRy zD>~{bt9rA$Ws)uS-HLbLU^Fe1tK+@Jw>vTFOQ;)9Wxq#urs9%ttl%#9!XLUlkAgMO zglRc-xP5)LNE}23!rrQIwv2$K+achsV9Hax_T3=`1Hz&CXJ1r+?cvT1!iJ5m-Feez z{N=Sv`uPU`Ub`j*u{+}4x~vnw^4l_#cPRInX8rI~s13hV0A@8#L?-3Q6xt|X+?7yB)~gWs5KKrNwl` z77)s+%CkbKo>-age0n$AcOT6}|I@`i{?dtP*j3rU>RMmDcfHD5x4_*T=N-prKty`= zmCnKX=iC_$0!M0`9K-2TfkDm1SBcyPS}p?G_J0=wwGm5BE!3|?u!oK{r0f@ikanz%HX*uAV;?cW5uDqp71S?Dap&sDX`uo*E!I zLx-_Yj|Q~2QqTYX1+|>Ff67!P--e8BchIma7-{uyQBPV4n@}0ig~_nmt5Q==;95EpBh@j?Vmd z@&l}>UgH=kU>3rhedZ&EWbYS*8P`B0m=P%Pm*^80D8EBKzkijolrubz`RcG(DJPMZ zo5b@>u0!!5Yc|EVI45wl?6Es(Z+dKbrLHCBAo|f`&BcJh9^@0a{7DC0!Fu#u`H|+N zDTZO&ZQ&?OxzaRl=@DE6NXCk3Fbkz(h_!(j zy%yNv`-CefKc!-Mc-_AT#F*$-oWuQr_HFryYqFi10wn0E$VsY$P+RDLb>9x|zlyn` z9iPx48o@-k1fWEh&VpVgF%~J3hY_^`u?w>e@94l*G;7UGDk7=#0LtO%uDZ}g+ZUC7 zv8|}~_vQwod!ZBN0VFEMv(LXDiGO3=0pd!5{H+qu2S9yzgG=OWXB60(y{<$0mB=r3 z4DDR-jOL)BFnYtj0K(w$SLioZbrAtQ=(oa?lf3OS?~HP3w}yrqQ8eGjG+zhK2$zVk~Vxi_u-V*;?AFW4HQiOkBtg#Mo}Xds|v6b7o$2t0*Rk>{XHPs?CzA(MSWK6&2SN4i)d^dWpB6${AMHs{-q5;V1q#ZQ z^Nb2qC8ZkdnDOe3>__sqychfBM5Fmlzn&|e3bu3MPyCYz>TXoG5(t#YM*42To`oY2 zNE)KhcqcEd8p(&)FIJCrur*$EDd&6z$@jEP(V~_xg=oE#7U9^rzH&8;YcI(Yf2OOy^sI$qRu?5uqboh5564B|p z0dMhjZHf%>uX3T}c=AEakoG^B6nxO(QV_3sLR!*l(*28IR2lLVMwL$$P059(Y+9bp zaqFhtt)B`sNHkQinSnN!0qXt7)i#}vev%_yUV^K){I{Nm>5RQNN0e$$5F zIg~7a&+~a=)8k`2IWdGV;^%tF8_a_FW$qwl^)@$aQYs?4EJo@$ z1JAlWct)SJQPyX&5MWg!bS6$aC2RyLA!3#%QgH2vAt92oTdh2nH`QwK=Lw!$1cJjw z0-WDgcXeD>I6yzV9kJnfx@K(;ibnA=EL5(*vHX00ZV7j1e9+a2w>Z@8ZzxzC(UUh< zRk#*C`UnPE?8x$d4#x%d-@TI)JzA@$=Mk!8H+)X#U%PWlr2Q$sd?HVMyYf;JHwMSC zhW)=xwbUg1Vpc0raIG8jsuKxW=^GF8y18~y*#h+R;QPwKC{Vz?&*Z`&2gC^m7z`f{ z7gn-2V0Dl-a_UU_y3g-zbtcYz@#b$?TO%dD`3omCS;fGa*IK?t0CQiK3B8S4q}!)Y zHWRAFU7i-(X!(?$=_&mo=Cc=ujl*Io$h;Npwubujld=@Z4&Hjw;B-x&T>pXwmkH|Bd;T_J(s z$u!*+X$r2uHYknSkWq|7Hlqa?6_%YZE(Ufce!~&1gV#MZEf4XPCUc8xYnIxNG#T`* z%lldI)6z#q6VN~AX>E%wJqK}YphMHtgm-@MwiAMXD14+-f22}1vf+}1D90Np4e9JZhGq|l7@$TGIrcssCblm+Jec%BL;Y5B#PH} z$VA1r#&ojB>OE#=3YcrjtrX*{75_(%ZC=4+aFvejuR``#C4{RIxO$4a;Oh%dXnMEN zPpzD&*xukf*h%Qby+|`XPpPIQb2IUmbs+{jW@SwYBu; zOqIBwn8S^t2&y1IeoD+5+|{U@vWL8DIAfFfg<9G?$=2WGPLm2ZB^5u;8)MTxXX{^X zVi#O>EQZpehmitQBs@U4ciH303;^w@W8a2(#~tzxVL)*`Lh8Zmd4>po+m=511=29R z>ni5NN6mk7e#A56W z+6e4v=Twv#Qwd1Qh4ct<4V-~)gAlZy9siN(V%P86zVQIKSw4yJB4`|R{*pb(^3o!+NaT{EgNwLpoQHtw(nIFX}C zW|c+4n4qHD-!U0?_pC*Y(x8u?Pb6qafD1utSXdvOrwG;&#j5g}{7s>vUdt}~H~fMB zD%ssQ8wy11m*IWi(f|xSc2q$fqJIXC5YP%zgPg??=;RK1?eVS@W|f*|vZA!^xF7Bpe|!{4dphiG&Z-X`I3Si+NtS z1hcJXGA-U)iD99Uu)h(Puvn}X$&C1fR?^m*Zs4oB2+X%fmFoV1_f z+yw+u^SX1eIBSyaj(j*&J|yla>5JAEj_ThX8n>KR&2*mLGA)BKTtRGaS$Mk5l%LlP*_8xfQj_7LHo+oI7# zHBk9S;AM`fTNQSzjHquik%1VDKp$R4rD2z9F)aNkT425XkWHN9@%&!BVe4t}^{D#a zKEG?~lw~<(l)*&U{15pRn_2To^jc7r`Sk4?sWgjY1jDaQtuDM?lm*B)yUqlHygFnM zN3Z)f)PJk5OM|a1F%o!Ks88e{`l-U7?6uRWH);xv7g0g-pRdd13^bsC z=;}U9?2PJF0CT5X|5Q}AujN`SMvt44o@gNQSnrIB_>nA!SG$2NvRekp)9P@MzcXz; z*^Jy`B%Ro=*Q{Mz(w_ZeK@H2Zw$_?VsOE|Z7xBHXCU5t5gUPLSO1?Lzs+)RMzK+{E#x7@w^iQl(T6KKm{;4=c9UFCkfXDCmV zUCf6@wlvu~WFOor?A15AiD3xn)z#}N8i-AM<|ro$u~3M*5lQfGDeJXv4L?a^H$}w_ zMKq`Mn-csD2#|t#%_F(sIVIHXtY2YPW@5%;;9V5GJyZU-_$7+ea$vyMNGXc^)13;v0=o!`~$s(EI!!WvK@uQxr}JRl(IwPHcBgunyTMtdLY4cfKHc zh*1`NKi9`9Qm8#qnbB<5okVt(_XZc*yXjpW!0SBw6P0Wv2;9jfYY}@eG{n#|Q*9Wr zwy(dnH#7+vpOT33!@m@th|=7mJu=VgEPZh3$+u$MmNjCCDry^q%L1oN zAPXJe6yEO5{&L@XYzC7U;mQ7*NYT@54h1h5^O)dIrm2na^Rj|hj1m(nmyU{XiTdNr zOy->qZL~1)5DAeshVq7lDl_ov*4ZH+5j8ylW7(IqpZdBSiEbAmoL z01D-850%}I^?=zX8E84~FSizt-)*~gXcr$Rcw?0U(q~)=ouk6<);!AZs3PzL9sqK= z>wIy>I~gThxm@pYEwR~l^X^h-y}f{YoPCRei=Q3F>{_fq0Sa-o>zu%^dy68XQ}u$3 znE7iZxV?CkncK?c`Z>l=*Mk#FkKg<4GW*~D-B+*M^SbBF2T)UgSUd~aMt_OWC18@nzip_=rA;(Dgto8 z&=IhPm8i^a!mttS)inPjsjt+etnfQw{A_|m7HJnK0nZEMN>GEXQah-0f{AHpb9sDC zaA3yAELPq|0z*4ljv-igz05<`Jz8GVvlUiDnw=336FR2L2fu2J@%+=g9|an(F_WV) zNV>j#Eg$k{-FaQcZL6m88;{zO`O23!*L36OmnKBCm%*@poac28vI0j$JBM|OTfK1v zHFgf&*P##9wBpuZ(!816jf05CozGCje~Z#ZVTNUomm*VS1O=TLZVsqwO<|x>lOP^N zMA%Q_b_8jIM+VBftJtjO&1v!fG=uv1+;s^_hE;@ZqxD)KAN62D6s`xT_l424(B7m)VTC9?Q?%u7XYC(~b%4 zu|c3*D5Iqhmw=1#0jFj}tJ{)0r$N}R=Sj=3c^6n$ReO`Q*7oFzdfdsJVPd1dkfRMq zO;Q}PkAn69zbr(E_)BMcF@vPl6){ zh!XQM{@i5|Hz%GQd55?P`o}>LuJbVoqyaQgZ+Z1s}2U|Y(!b+rh60tOcRg?h|=;}Nw+=KV0xPz$o z9hcJQmW6#NiC`#z!luRAT-I0u19e8|N8mN5;t1{*H=FSFf+bp;QT$Tb-r-`zDwkOd za}*d*`paqV@~nE$T#OQPCX?L@Fmm5Vzv( z9i13m6;_zCkf5MuF9JbY`fxRU2yTS^i-b+EwFHq0 z3o>CQ#`(Z8_Zwvh(9Vd|Q4klI$>;116jpGiwy#ts=*0-)1CPQn0}#W8FTy|yro63Y zy5Ibm6KDDA2=@iej5(oB4evvp{-X2lt88~Mt6jaPqlCQ>P+fRe9tGRX!}X5JseU#w zzsPx0k+n_aQn=kVLYv`t1AFlh@Y`V1jXD;u!v0Viem^_2kd4OI+~CcF4<-AM^~zewh+q!wy6Pq8Ewa zLlFCGa&WiWY>(evma;RDOTueqL-1tQG-cnCt!)p_i}v|}E4)f88pAb_p!7QXw1%|l z@_l!!!w(;;0fFHEW9yv)>+0TU@7T859ox1Wv$5?oY0}uX&BnIVq;X?3wynnIS$Y58 zcdpJ&uJ*;wUUSX)JY)REGx^3J2`lw?M)~#ls|a&NO*%pxgC~wTem+Fl-xBnDt^8E^ zoSo>cn7Q4xiPTF7imtQo_63J=+vrVZZ-bZ{}TqKyp$l6}sa%G~46Bw-+VFVR4GbUHzmn!AqnO zfVmvA6A`Xmk(w$kSkTpdl`9>KIj1K6ut{|GFX(s#;bM5=;~DzJYJv$)6K>jc{2@D} zKv&8&v;x8U$QP?bT#q?yE`+b2A6=2?aDoR@%9ZNpVJfBJ>d4|8_+le=vDD8RnmUm2 z6cMAvf)j{+`v=PrFS0YO51gHF%9V)2UvLDmfv#GgJr@JQ*OFQ$#Sm*mz-Rl8&Ib$Y zq|X7D0qqu=gw*RhNA)&i`G8v16z_!z0zBFjHW{)j-H{g6w_i`dg=IL{OL~%NxlJCA zdxHkUCZgCs#Hym$*bt$H4*DGQq$>?`{@d+gpN%8&9DuoEt<0wkWL*j~FUzoQ=hNf+ zq42Ah((4P~iq9o2zTc)x-C>=dL(Rx9#Z3HY+YaYUOGRICT{L{l6|2TOOuo!t+2QXk z?F_3n;cp77br^iurkJgiP#VNv*FUYS)=D1r7n*hWYhn_&kPMwVygZ+`4RbHrt&Qey z{o-@DsU^@lc*`0^rianXyebNLXx5>BIR(cZkL2L6QohftHSv4U=`z!%3mSNn$_v)e zkhQ>tmL5NLxCiL&{NIo_&@ZjG_PF=K9lJ2i8SnRbhugN@KK=CP$9E)pZ%M2@nigOg z9z<62hoy85Q$tTL4lNhq#ywY|l|Se$4+D4iFCYOSpsWf!4+k!v+7bn7NtV(tS6Byq zx;4Dm1Or>vFDWuWi2e8Yt)!ANk+EgjFnM*;FJshg{_HuXtJ@v4%N~3zlr_yCB?V~E zot$h&rBB!3PP6OCc(mnTZuSmz=bf8=>~-_OZ-ZU-ETJw+!?$4*C1qCv@4+TrzBIK~a0Ry+)et7&#@c8AM^Q2NU=Xnkju&W{NF`fTmXwA#y@g4fS;b-_d zvLPlgc39$ASCxJTdx7UyS5pOt@;&U1dwmI0%77Id?qpPuo}Y0$3xArSH1hR?s)5RKP|pn`;q&5b7~{ZL;5C zmUdskF7$qrHS(Y)qZB)SDM;ee`6i4Ips&r{28*?(Kk9SJf*jH;a^4WhM z6YNiYoF_N-_}#toYc3hDgq5Lx$dzR2@o9OD3t#yD2X*Eu-{ z37ylw2`V4rI~I}&8&)MSLll9vVS^RxG;#ABG?&vzh~Iqvc*&q;dpN$f_H2==Ej)feeyaLclhhJnRpCM`5AH$%F53e&bzgQ#04s%UzU=1S~9}_OQB}g%ot6e zp9}(^sUtEEQ&-Nrmj)@7b+Pw{R`{eJ@XX~d58w?jZw59P4B&mnv1mlVG{9mL*OVoD zxL1w=0>Ki^WL$k`1Y58KW#b&kDsx}iX<1el4+tew4)t>4(Y9AAU zPy7egqMs;3ZtDvRNtyXp3O1%Tbush7u3*~TYf^7~&4VezSLzcA%tn2toCe9Z>DSJ+ z$36aGE_Yg|^G54xEKEUey3*QDA|gO*%R(zP88$*tiemE7R5*@Q8DhbPs+cC}?D5Q< za96)b{f+^R9d_WW%vwpftdw!$s+bfbXK#B;UxmWFCf|vV(6%wmJ&&jUvp=#;KjzWA zujpEDPCPn&31@n8nX^m!G2`<-{s04JBB1~W2Nlh<{6Z0hqqj2T5%!D}rTP^pK4c=# z=$H%Mc>9Vfo5s%*oLzKed>4yjniR<|SU?K*3Mz+`!lff;f?kl}1#|MmianfjksnpZ zHD!rR>$-U+ZnMuFg-r9ijscSx-u0HLSTNIuTu>dS$?5s!_~|n2pMKp@*gxE&zXyS; zW9@5u=EA&ElyP@x;=7|LhGi!8n*jUl+qArdC`g=7hyv4TT=w2m!o*G9=-aXPNa9m^ z%S|slpgL*O>JAq2#9-Lw*CUr>YNhzsR@NieAMNX<&uoon>UV2*y56fll7_W6Jf*nO zxjZ`qw~Eo}s@9wzPmho47TZp>h^E?UuPW1t$;)xWd`D{HpC=!1FhLLljt;Ehe%@dC zng>yjc^|$E$vIUwM{4}=qSF`mGBfuyD%A9oe*6bPkiuO+{frD+us`Siv}^j@rFGE{ z5k$!tpaT3eBIzAtXBbK5T0n1%CJneham^yjoR+?Mx!?gy&G z)grfv1@9A;Q!9}y9c9*=aXdz1pT(@?kPcG_aA9vOiUoQwH7S1~c3p5weh7pCgN}|} z(fMUr7Km+CFd1YvP|T?1e9w2js+%3nlH|#Jv3%|W+&LLPNh7s(RZ{8-U>LeOLrqQ@ zc?J$eK^p4BJ%S0QIPfN}?UNq>?u0C{B)uOI&z?fRau@yVJDTsjwZO<8>6R}J>n(ndW?znnMcP#yh|JtcgH7jC0QVQh@+Ok>z>Rda~{0 zdJmI6c@N_kwB9oo zUb`X*l)zsinc6~`=Sw4*$`%F)E7ch^wqn4?BT|$ci%0nCAwveg$hNXQ{Uhyb#r=8w znRjMyczU%UP0=`sLouY#3eqgP%sJdKIEG+)N{?kCqok$sNWD8(wqzRu*_h43IY??U ztv;?RC||^XwQ!ZZH{VA(YbFdgC|&0lP}}y2iLjDhMF}aRVN*+)RW-FmbxvlM9FbJSYGqnkF=ltke21%e~q8MB~e{xdf>1rujp&8 zF3&@w?*~?>qbycwy5s{!S6^@*G$WE{U+@?}+9L4DFP+5q*Q(1V%1RupLt$q;rI+Fy zLSdb0r+<%mYN-??R4V=5+@Sj=NxR6=kIPX@+&~i|%z!-lXR4H+LRTAi;waxRz>^WZ*IK z0W0QdemD>{>?;X8^v>7dB)Hs!F5x0uZ;quOxcX)dK>BjPbC6kBkKzkBvDfzrbF>zU zX+NiaV`@I*J-sCn5kGoMq>4m^N>}MsrZQ)f*?U3R!aYoi$w4Z2+{kn3pPW`ENb*<+ z#}vFh-fYb^*M*w11P{09w^hq4pK=Q{^tMhp18s6rRDWM%o5Yj_&NCB1+6vo@w~t?@ z)()U(mvdTfVW1y02F{y)2qqEp0G{G0F3zIb&WE?SZ0A@^%a8Bl%=h;buiKX2MGt;8 zz8>jz)ch8~2~#LpexMC`bJ!Nb4+SMU)J|fV=%6jB>bQI;S}(%*+~MTLPKJiU^(fD# zzrUG=NpIiA)FYjCyyZ_eD5){-A2*2xu{p`19DyyohkbbJqn;}Mg40BxY~Mt%D$x=( z^#pj!QB&1iA0s6)tcnb%JPc64rM+{_t=aP3yt$ePm@;{N^DB4(mHA_9W3FL0mZ3VBQfpAz7S z$!Co_=XsG98mkdLQnpe&<} z&2Pc35%|5E)Ov&7bj98WnY9_%)(5=i0YFE5e)Bou%`Mo6O=7UOx3P<%wP1qAIMPID zv(Ldju?n~tHtM7Ce~+pBvxEK87ygypG+P@mVa`GAzqXy;a+aVG(Yw=sTF-Hm$3sDYAVy21N9sGh&iPwRt!$3E$+^P%1%L>F67n76=yd7yV*#MNni-Ckey;cHlDJv`yks9|ZXNKUYr zk*_xTs-NiN2)dR-{C8(YI@kD{^55>8OSn7C`Nr)G|9Dx*0o%z>hfNrWA3uydI*isk)U&1-A6BfWkQ%)h!L&?|;DH6phblxNQ-!3~s)!}hl(yP^a5Wg=z``_r zxvEN>8ljvAlmKn-R=PC#SlC^qpTa`Wc>0A{Ep;JMua3{LV){*fdFe# zSm1E9hCXClrTalYywa;R6YEG4C)Ta6;(YF2VAVsAJHp*}adu7RW$(WMYOx~^2*fq0 zAT&MC6Oy4<7$rrW{qO7;jbjnoVUb!DKWogyW3a}J04bj5l#i$(=af15-YMcCR_8fo zYa_hqwPUp5*|vej{Iz53TF@-gD#O0f?{D{-1?{8~lhJ^e2A%hJ*Nvkc>}z>f9lkE6 zdGBlR=1s_?m&NwB*0x#-7YQywJTh*W&Yz3;TvS&(Oh(?zq8r$`dbVw z27;%*fnI#Bzxj!~h|L}cR8uY1qG~>_Y`4#9!aSlo+!!0kF&S_i0 zD=+xxmD+}8-gs?&KdCVoUJf3yNht$$IR2EX3evEFD6&IPW40;-QXO{*^n~7Sg?JB$ zpgx8hFWAvOpE@i8ytp2~IS>_^cI7o1K<$4RxU%59<$z|sg)KwhL1HCFy!vN6=NVGL6=&=dyJc)G$jt2Y8g_(R%+dn#9fq2; zPi7=vSl!viN>KTzj!ggHL6u8V)}hFK_6k9Pl+38bYjufVNxCmC4A#kPM*B^ESe}>Umr@D!x8JI2?}o zP$`5_b-)Bx2`5hq^-Ud(O?`5Hs+d?4XYP1E{A54Agpr400o+V~w|ghq0~(zv`1RL1 zZBN|MXD6dxx9s3B^pxiN+(Q}y5yIcD>GbvOYMrYK*UQ2J*ujD96PB^}0W4vI-J6SI z%7kuA5K(cEHt;+!MiEB)YK*XeF%m>%2(_EtC`ZI1H`(;>gpN+q`(f~yz#-6aYm3Ij zg#e*;{+3@3)C z3p71}H#wXJbEv)#6c!u$m0UWpg5f4FNd;}Ec2|e zD2en#l~uY(FL^y~?s`9<0P2Oaxp!1&SM#+=uXx?b(_m$nGze%DxInc^3UI{JR#XV| zzh`=Z8wmwrl*T=TnF+vo(6FGDt!}~N^`+mR|G#^>`dGiM`lA_k!&=xk)e`pTFpOD7 zib^>C{txsSR1=;40)H7C2iYpHJ$Zh9D#%#0O_$fT#(utH%`p=o^vwf=;j2U$8{gG| z`L(+%;#0QJ49A97fb&HTt<;VvAzqe<+YYP=7*eA@c!<%pHu_xxyg2!M|FUSLCZN@6 zRYn^d24g*lK@KdJCJeKciKDB^h=*+t)|3dCG_RS!vY1t}RD8MX@JU1N1FT+7wN;6^ z;s`cvM#v>AGo(fZYs5vW2_BxRMg#*z-r^F*@l|GVa8TB( zuS6jgKwlgUE2sj?NecA=$JQUP$c;O)d+hN~;oW_{1$3l*^5z)jA!vV!+9N{N^elv&uWEU5cYDa7sb^!zT<(bf*uFwRq#r>LoUH)@kuD?qMGoXM1 z7ECi{4|>9ZV!FpS78aXt2Ov)z%fXiizYGh`R_zJ9Hk-NLAG#D;m|6^wP9_TZ2GSHX z89k24?2{M{EH-La#*ej&o@Yc$Im&p@fP>EHDk^CTeP}8PoP#>T7BiU(=M04_(pv+; zaeo)`?$18D_T~E>W7;3Z$+@4ir^kvURZDT^%fT`kpV! zLQwyvK3$;Ukr1j5`dXaN9D8OkX}H%*pZK*`oN^j4G@qu@{bD}RaKK7Ktu=K(J7xhv zMUOf^0{#8uATU>~Pdsa8(rEhwg*fi*rF{#-elC|vU1*nS4Qgt>mHo-UwLZS&@pCWh zf#<-xiF?%U8zEwDEMStE^#6myzeZ6=^q7pbF~<`9bOVX=SiGGzFfIgKt|$v)Q(lu4 zr%^3;7PBm!m&eW2m_3-gXB@;Lt?SXEh=woTj%xOJm5KQvfof5;u^hVBBe+Y0?eQ<* zt-SQyE|w7&->9@^3QU}~{}sD~4v%!cWyIARs?4f)h*Jgm3PogRm-N@qD=9+#I2nW6 zt7baQBTD*pz>FUAjg1t$WdAqGj%UB=sZEcTccu+a7_geeLjzKR!quSpKiBYw zKnz2b>PdKg&yj>{9)rtht)jFIn_mq5KE$6fO>;HE;m8>bg`N_m@ho2*|MeT&ENcei z0WZ$JF+z9h4WgMDS` zG4Z=4M)e=aq6K$cHQQbApJ_3aoouyj$RO zIU2tz^sH4TpL){qki)Ls6N6UkH2{$C@V+3VHgsMxrZ#+DGCP~4VMbyBWp#M;-7Y16 zDgx9t6mPvLs*y1uiFf&}nq%RY6wG%Lx1i57l~o=V%Cf`7cNN>5pGxuj0Od`epc z5F~F~$?L(7;iVDYv0B$yc19u(hG=p2T+SfbLWCCDm zGDR7d(RMjU*DTk`ePNUvEPJlL-yb4Vb(55R4F(VxzjyMH)o>1QSEY2nimN{OCfrd$ z0Pl`9Gpy@r5sy5%@;cvg-H_?@YvPR40vGZ8NB#1fZHd|dhd@8!)6<@HU0dqxbLlbt z5Hi%h9lnU1(7Zg$#~~l&U$a;IZPgXvP9grIpOVrbN|kcTZn1zv{&%NKt?%krSzlRf zi_ujdWJ_AOAg}M7joIu4<&a>ApMqIt^<*b-9RwU9%Xi=xlfQo-O)qDDwL&E!AdS56?%iAmA-n~haT-Fsrz_Qot7`jc=TWE1$ z;-J6H9(^MN-5?br24W-F1P-apO9TsaqvkT;dP9MU_8gD00gdw+%R%7>8|}y2ylC60 zH0PwBB)XKqDq_QMWTVT~G2VjG%_s^qQMuda2Ed=FX8%tMLvgA$Jg|Sa`OKqDTZ<8< zPB9(z{>n>~>n&;1#?}LtB1(GK_;TtmP{-QzxsNxl~&X&MZ&&M}D zH$wa!>e=TRTxXAa(E-YeshOk1=Qv90sxG!-M1^Y^D5=yc;7c{=Da$%fdE<~y*0ETi zGt}dk*h)k5{`ylfRRv$bl*S=RMz^9k zCvmS*ieQa=g$h;^7gi9Yo2;_xuM|!)W=Y4S=vWIBfI-eU?4u8jRw*0z)59*cf_Q*# z8e^2{7+fu~lEw65Bg*+IdGoF-G(M9>YbIEsB6Jc9&I;L#<1teY$X#%aMpgTbrZIl< zB*3@cgkd2{3A?vTC|-X|Xxx0) zHvY29h5(BZ6CYzk5hQ}7f3izdXMC9ee*yh@o$OE%+W13NSZk5Te4oeeBZ`K)F2|5q zVq|l-`R6z{d>~~lD?$Uxy4;>bo^?S$ASti!CxX;JH4r&*zwd_Qb%1biu(|z_%J&pN zxE4n2{U<+bNWhVg8+CH@9`lPfY3|+ZOegb;#+*E(O_iN~_0N(DP*=z3=hBeQ*)V(c zncX`VH3LcTj=K7-8)qzQtK*f(c%nzD8?e~2ro^Zq7&sRPbV{=h7fQvbqMtOMJ2rSy zYDge}=7E`;6q170CYRU$KUU~R{?5k?jrcwB)C1M?!`3UZ%NQSKF<(h0Mq>tpsgDU7 zCe4rT08KBdZmPatu{PH7OE9bc{@*!Ir9Rg}>D@p3QMcS;Ugr}l zs24&|tTg*wQ+x(>Z?3}tyDz+r_L&Xg5PPRL-(=X}2TLBZi=E)vJN`Nn%-S{*?b)R1 ze&Ve|HsI1WjJIOtjUyeUJQSMP;o4PNj9Qy=UQR*VOr|0Kyxi&*wEM^oL(0i$S>>b8 zR4*B;EqYFAvB+VtFfW6b|AC7xAtPpDTP9_f0+oU=aUI-j+&Tn@>q?H0Z(}65&`ko> z+E?m*@02tZs|WIPm7imYgOvVwD)L!?O6|81_3z~6XU*}?FD8--Pe<7TF=U41qlG-z zlEU1LoM7@E8!lU<47KS(5@~M*gXXzBpRj>*6b<8$Rd(fs)^5X-S{)v!C6h*>{FSLg z%|m>)b^myz!V8p~oX!Kvb-?4**))I6`LGz8IN*%?N=_Imd)&C&) zO1YBiuBx6rOG3Ys^2;!hY)>wT^ocwPhW?ifxQz}fUuPW zL#Pwny`b&|v-eOOWEDky4u)ScQ&Od^s#3Xt8~8`N!z-29Z85DJYsU|@nint_4pWvx zB}C;&zco}2Ji=1tB_enpz&oc4uhY-P`F0mos*Rjj=gjJnag`u3f_dej4km|g=4PYy zx1F1r#`jQ6SWO$X`OdA1F&61>3(r|fta@=2Fmrm*8+gd@nYF>xfi8N~(EB&K%EJJK zTIyYVGVkf40!8mXyxNAVekiO=;h32s#Gqcg)8&5neRZy>-JC6Mbk5P8dcC>bpL%1% znJ-SK^Fqf(PFCY8WGXFn;yYS2`lP|HzJc8-z$~2&Q>`&)NJMPo&`p*F)`KlCM2F4D z3_4O{fbOIR-s3^2uZqnp->dxmy1c0Gv(vx~<^;dTR)+m5LY7gGiC}BSWluPaYX*X0 zkQ4NTpC*{haN$7JwuhQ(G#mA2cx>fgLg(J~Vd9e`LyeP9RwHjuPD0sBIRs_Ala=q%fSwi)ap+WE5y#VUMoYxnMo=5Bb zWwhvPR~o#=qP5I}|BKmThhtRL*XfXN9-Zp@NahK^3kQrd10o{ghfBxQI(*7{2eL;^(eU@dm|0 z6sVf(y(X8iMLMk>{t9kn^ZgSE{f`Fyy$TB#kw^2MLW;#&*US$e*ddHLGyS+_;pAup zyYaiuyM~#ay&26-eKZ~ydXobAw0^TR(djj=F4GE-JVHYk;^&k_R{Jnomjl;+<)#B| zQpNjNG0*Fnr$NFv<#_66I<+$2%%0grVEPG?GXs>?A)qlF#fl}#BIl;g!?6;8L;H96 z7X}S$Riw`Sj_kecny0VUv73lCMN0A@nA*d>WIW6jT z;YKBeN%t19FA!O8w!_0d%EYc@x?0TnctXWsg z-@!-$opL?n`*lL{bEwm`~F>c%CeWn_9l*yE~u$*^30QLmO!PWN^gd0_w6 zD61(#KeAbQf=-LmuLFYE(WT-*r^Eb%OWjO5qnZvskz%R0$6;jszN>`+J%qUu*<@^KypIefe>^@nAkx^!{a&`kIjR(a zBnE@q54_eJIK;%TXoMm(3#|b9OFTTtNcG{|n(00TQ5KNrQQh>{=AC}_b_=*6zk8P% zpx1FK@AnM3qxApK`J1WpSFC8cbpgXbOh2dFvxX5WV#HbwI+L} z#`DYbf0tfgn&NzaW%HOGLXmF z7VKS92B^phne*I zXAFXo&nySREW%Ktdc`(B&g5`=op&pCfrndb!WvW#MS$r_30RO3`jn4RK2E9pYtHlB zV&H@5+kq8&|3ai1P-f{=v4WH`qt@8Pw#2a-uSArssR`hlZe4f~CgY-B-@D%zJZ0=a zr9S#Kb|C%HTwjxnrxlfEC#%;$cu)+Dd=J9?u!4rWq)RKRPF%#+I(Pri`jp`}p`Tbw z@7UPc^jg1y9)M$3uii`3h9n0C7|qco00g*tJY#Jo4^)~9F*ggkX%s(C-|EIbGM?Fz zwrFr<(2x=LdjWmz;s3L*rHD9@_%wP6@;9lB-Wd?QB2*c?0;*9oQN57lFIA4CMI*sh z$-^HU5ixFs<;<TM2g=M@{7@K z&zX`^CbS;AC~=%GKa!u=_F1vr`KGQI+|H!O*_Iy%#JtqRVChE_v#Wv10*qJ`M?PKI z04z?---Tqecv4A#1jR;@P@>Sxqyz+2BP8#6G$SD?7Knj~#6Iue1bE*d!yB_me1r^xJ>d zP}Bd`qsTN5_rW6(Y}M9rAXBpe0%xDlS^J|*@_)cVM9M}2aHQH0SesVCZ-t&P>XE#! z`jTI&)F$kQjpN(6-X*{!yuQc05!llJryg;xTQ1N61p388Lq&N6`mK(&Ac6Y^cS4}N zAdHXj%k3gen0-cBwEtVVse5<{^Gd)CjULJI*!lU5|SB@_2j?4 zPowTqfCHX2gpkXretp1HC91%S*#g@DJB<#~wBGE?~7iVDW|FXRvXMj7` zk>er#h&;o7N4=+|gTOO!)We6+es+P^IJl1VoA-6x(IE{EgdwT@Nmp zWgBij|6@NQgh){S72^mCe$>_M@7Hgy3;9OF=KS_o-X%xH`$n*qfXAbIp@|g|zJXoa zoME4Mi7%0$_1%!YN2C(DonyeSY33xoDR~rFTc*>=Y%r!@=e1WN_xeb^o0{wtaQw8G zU{2S;_V6x1GtvVF6{G5wiZq|Rd<80sPj&KV{wnDwnYI-$hudJ^{HV{8PxN#pK9szv z84cN)R-hxM=FtgoXOb^K&OgMw3ef*548t)GLsg0vUmjx^bqZC3OKfnwvoEY~rm zVzNwaHZ8hpC2cYw3F_M~l}u(jVEXQ}Kt1)1YRqj64Ezl!^EM8waQ~E*LB@wNpAC8Q{Oj z>*$8~2Tc`qC+M1SW#RPHq=Dx6zf7*Iyy3ZX{yoJwsJ^I^T|D+d&XnmGn|^uZZ_BUG z=l_PG?|U{<$Fqg7WxJB0aj*4s{a{;rF(7*hbD~5HOX2fCx!&Goz%S2~7m|{p6P@?T z@4O%OBLfNJ{2EOA)sk#u6x^EWRrBomhf@t$6p$|_SlyyAaIp?I&M(Mnv{ElQS37Xx zI5J?Xs;0c8j_VUrIpC$-unC@J4+zfi$Hkz2uj9LDb~3iNegax1a|twEMI5BBrLZU- zm|EE_>$xG%GZQ=BGN44KW*FYLp%M)OYR`^MuSC#826KTKm}Y4)9=YwWvmJ5O2K~bY z5PY^krL|CNYZJoLptbvX6|U8jK=wcDfYjmpCoI3pumIEv!Je%MVbhY2QyDF+4jLWl z3=!%q%6Am4c1E|mdDswOI_XQbMSX2!?isWuO&0x-2C%l&m?q(Su0!mOUw&!Mz~8;{ zdEdP?jDT)(YZ`n$FM^U)^jsF18fhQgUiWOkghK0MHj%zs!VY|7k^)`8o4ljlvmRxs z8)pVx%8Hm*6pa-6%BTq02flJ3qT( ztb8C#i@#(TFh^jm3yAd@P@2DT6gl*55K{uXq_bmpNLRwODxi1Zh~sFY-G)FT+H5cq zyjbKw`9}Awx9s|)q}P7V*?o=YKcF}cUB+T8?);pA%}cZCZT`$_aH`%U;i)i(zrYbk zlmuv0sa*?w!14ES?m2{oy(NA$yvyWt(LDS3sB4ob_dqMWH zz?h&}J7j>i_PL`0dXKo;oB?&+em(X-wvwRP@gMi!y-JQCQlWZG{=Ol=m9mBBJ7P0H z{P~ZaZMx(;itq-vpSgA-86>NyBPhe4C>T+@BBSfa`oKx3?XQ(f z<@WJ28SyiB(pLy*cv{>iFVuFBPy@5G#!p=xP=J=J^9vA-#MDQ5Ln{C+wD|6?)4wxl zaPn@T5tCArKOMxvAT5kMZqaD>-bK)=kq9U+`rVXM7LpmR6ARW7tGF8OHD9Qb5lakU zY(6e3f4)J#n_7Il$`7HCkqF_Ng=A%c2XjrcbbT41^BvN))d^&VX#$L0fGCflc(iLd zBoxy3y@>6%o=Sr<$^Dju4kkyyHL}TM^fQGvUQN=g(K*n_5dfQD_NCRGD45%|rRKaf z;X@e`a;zpiObeIh?=4)r_9~peg5V`40Y0Bc+nPkAIx|STEfXFFM?9uC%bZ*gxK2X= z3$KEJKQe%th6=MuooiHFFq6H^S1gZL8UW){w?9J>NE%7#zPf7_(|SXX|92P28t4K;#nMNBqi3-u~Jh!@m=Ew7ZrB6P^x-;A zmR`Vly+Sr%9i784Hb^C1_5?MOsY|E0ZqC92(`tRU7JGn+*BFabL8t)eWr)hYWCX~) z7_;bzN|H|y&cTm%`19GSZ=b%HUnRBB`V=%&F2*!Xv}?YIc$yCCh}lO9)C`b#6+D;A zJH6PbO0^cQ2h+Dg_M{Pu9qVC1DVxOb0wk<(t&As&TR0Tbe;un9DY$C7YX}BBqj?p4 zQnFMlv>|*HnIL!j8ca>};t^#<{2_Ser(bs3R2w`yY=HRXl5!=Q&4|PdgAP(a%lV)0 z{XieVuo%Ac`4V4@>fd&Qp!?CA@~d=(DkZK8nZ>7UXS89Y-ZXm%qslIE;Jtjr)6SUeNZI>HM&y7z%_ea$xl(dl1N*TMU`w(Q2!t7ow z$HFe0@tC3D{EPot0YN`v4D0!jmIkGd4L#QmjrD46l~``VgKhL;gU%|A@Jk&C60k_K ztNh z#R%5SEM84JIZA!flpxzOHkIDONJ>PDSkS{}Wv*DFUK!W4kKpGo4)R=6IHKfT7)XeR4nTxHcoIb)UL zhAW}-#5>iVMiKi&FVMljfsS9XZqHe`F}*Y$SKQJ?bUt$vkxdbK9aQzAZZ=i^8pJiL z3&t$bZ74)IQwsb@U>G*PZZcqhWS>%fxbWnU#C_nWCHzgXV1ciu7z@jP?^l%sEi!-I z3w9J71UU1K%@e{Vh68n7hMchzTqK(+B_?nBSSs>j`q;F60dqPKkIWd`R#~d==V!^N zw_h^;IUShjwvZV=Y@I^sd46^C3tb2rt{;?STjCgOrw#V|%&r4JTk&z(4n^OZLFJrv z7&qiMO?&&{Tu}#pzon`I0ri+AH}B!aQe85V=GQ7vEc|Da!j=RUyXCG1x8eA8R*_sF zjdu7i<`uJ~a9!&2eJc+)qMRRT-#a{PQ=@Cy;UAIwETQfP^}Xpj- z-P&Xb+0?~Mu2J{mMhMoOwAw8WCv|K1C&Fz zb%)?iiIWDr+5a-Y>hjs`Qy3ctml0%?@UD9vwOMtkh?llLoWK|8?x>iMKK#oie#`iuqh*%^+6=8pDxiRiK#0d5QdY?4?J43*o?j42q8;D!yZK*dhJ_0#htVPK|lv!!2vNftvp% z`>RFZB>jJ*t#)^ef2nHfGH7W*J=wkU&sYluV1c>jR_-w19Fg4N&0DXAhfmj*Fv|S_ zg`#Z62SonWmttxIGP-l)r8liENXTm_tcFiuCgnH62E{Tzm{FpF+UD zG3RzVhZ6epBVr`76uv`+5Iamt#BqmF5zlgk5tWLeDSxmxUQ{^z0ctKFI(sDCmiarJ z)UE}nDpDDK`Rm_4coT!v`v4AYY`xVhDh+8cS|mXa@dwD&cLV@K8cr%?n!>~w0%Tb8 z>GI)L8&N5J9 z(&{7TIS6ijy+Za!(5y(=V_b{55A=Iuc-$ zk%XHmQyMt}pWcCjMz-{HbaiZSXx}Yo#w&eN?{zkxmBBv=h##)9NHvI4m7azJJL+5g zaShUF^-=svVaxRg1M_zouHfq`POLZofCnx?)XRPoHXw>0hITUM*@eZ#j`5EaeNb=w z)^7>ebnu&Sqg$DIvnjILHk9}BAg&53*IgL0G1!C6ql>vFT@G+0=k>KWPlx-OlzI8m z3%JopAGwatWl?}CUX5?rC)f=%LIdE>{39qI^PqD7wLbB)o~*JO^RZ0SGo`Z_#3)>@ z?^OiW)IiEMhcBx%33KJr%TAQoiVRZ5j26*|Tf;5@18G8S@T3V9f>;YklZF}plY&LZ zJ?>gVZ#YZOfC+5)`*a?LD86${LXNbp_^)Kc1QFJkME)jdgcrIdv<=%7m|_|gYiWOG-OntUFn%{5G|uJm-s#*v=eRPO#kRPXVR zFI&UI!2vNc{0#M01(!mg#P4$kuPaTa=-6s&F0-srsBBnl=WqYZNoc}+WA^hN7~RB9 zmdg<=29VScm&NVT*&CN;8xbVB)Ydw}UX{m;%yk9b)VBI?J^G^Ppu@DFv8j664~aV^ zgkGs`FWqe@trUP06Mp)t2e`G%XufWF|7?qk^9Q`(<|aan`i!_(E6VQpi9jyA{SzIw zDi#m{eBtoCE{%uKdP~&a)+eV#3xfjF=dRm$1930GEaI!g|1z&}ATS&Xv=5533wLyb z5$xqY{I;h88LVqpx zTnqoPd{Hs92Yg$sSCMcVMT$^_S19bJ`Jql7a-p(#foq(lSFfF+7$h;!boUvYk#5whNT>76P%}4K2}VWP#5)`+8HpR^@S% z5Tck`^?(OQyk*eeIROGRMH$l*Loq$a99aPvf@edyFmT+EXQog-Mx+AxKTt z2{-FL>N&bFKzG&fbOASPr3^))N`R?EW5aNMiz$F(bKZZ!TYTfs40sHC9Gq44|Frf{ z;L;TW@GNbD=p8Zt@Qe==K5NKDS|f#Tmys(uKo1Cm-n~;9(`eTzTZYS+x@5S1Noj}Lj5Fry*g@riK>;FKMxeh@XMoC1#n)7UiS z^nMJ-OZE=9W=;OC-6x}jNA29pe65ka6C5CfP(Sq|vLM`*Z--qx$Wo$77zxSCRB=S~M2uc-O!e)#< z9i3l(YoyJzM%%s1xIa89S)1`=3`MDtQhPq9B{j(`ef@+Ej|R$u?C2E?60Tt`sKOE& z{twbR`qKI3D8#p(#^?Pk&)&{cDQ5ZJf~Mg+{5W>QZ=r;P-+x5)+pFhiu{0V2@Mi(e z;!zv%iQeDahqLX8fk;C=r|VYgS@~a$+w2$j&YxS7Kwm)nYEmdb)0$Sb^cZ7 z^N`{nJzRHxn_&>vcnOk3inO-9sa9AEcozZ`FbrS72xqwYxhQ_fJnJ&MbEE$7}_7QoSy1!}xo~iTFnmYl${6<#2!qG(A(P zMCgtPD0QkTs-M>$_&e;#DSsAe9p!X1r#N(7c54>+V`wz(l5xTkw;bC8-dpG}6#o3- zcDhp&E-Lr8=1_OUU{TfFSm2vGj{x!Qr$HY)K<;KRK{bP#r?-^e8C0WVa69@y6iq$ToTIHc1{)Z(!@SBlC)U~ldx_m!W#IDP=n}+9 zoa^lNWS(Rz;jsq|BW6kuDLk0mx`P;iu<)-r*ICg{5Am+WDGLI2kWMNvW%PgeSrkBh z(5LfHb4$H+3sM~TttS$+TjS`c;PS1L&f$)oU?=}hoH+d|Y$|`WyOm18>xqVl^l(Z$@ouFTY-Gq-|Qr0;&kD&Z(TFZ%p^J5YcTtBn(N6~=W6$Y#;wyVE_K_!3A` zH%)B|fCg~4T*9en(dBTzX)iS0Z+xq}vHg)JujuD6?wL?|Nb?y`T2V$7LA;YPQZON3 z>~hhrlY}Xdih=loo|FXS{(XhC{{P7)4SFaWQBzWm$W`Z*e?Imj>xdO}YVu%w27i&I zx{t?)WNZl&2=t5rJ-w4HQBcoCCyCwNDIONOat+UaRs~JC#-Cjs<3{(<_BnXquz}GM zV3hqoCsLi{sUGebN00swTi+O#`4@IuO}1?}*)}K7WZSlF+pYD@3b zne7)PxNsyu|MQhYVs8MaYFDT{XX?>N=a=p60p9)F{98qdcm_i>#v_{OE&_vom1=5M ziB00UlFwKwF`zEhzIW((z^iZg44ijx^ecA3olTod8BeZtn`!cBFPScU>%R4~I>ncFMXXSjd$qgrEq7}Bmouj*lACBqZ}$OmjmWFu{AVi`(M<>M6XVXhe zK-in)QOU^yu(W~H=@%b&pZUV=5C=vk82P;Ajfdjvwar2L#~kKubn>&#IzrM^cIw$E z=l&h>xix5XVG(;nN7l@Ac;ip|A2lmCTmi!!6V=WQ_|vZ9hGLRayY8m|Jv&$5@danu z$MKsK(0PrNQ{N}!xYKw>ignQ*#Kr%IgXLP!s50dij!YIW+KyOsdz&f{&k1!Szd*C? zTQcaf1b_(Tj3a4^EdmLyhY0*XRus73T;o$Dr25MhE`UIm0YYH!9li-9Aaqy6-I8t| z206K=Fy~WFnqwSyQj-sSCkpnKtd4hWYA^V@Vnw=VB(hLmM80;qk^AKZg(#a@kLsWI zy$c!$viWE*q`9nszwL^vKV+g^p)~aVI7<>>N%~25ndiNf>HCVAx`E}%U0s!ijh2Tr zx%sD{J+T|t0sF{&aixvmgVYlz8k_@g2w(<`OzFFoxz0V7Y{zV+nq1Jt0YLFOm#&u- z*j~vK_8(2K=<6IbIAE3VJ>@3*q!U-omwclF$uzz2YeTBte9nQ&=|4SDoz_jN&4!E! zmV)Ujtp*V)y0Wtc{?)2y*K6A)#Bakn#f=at6}sXnDvvi?kb%r4AK-0X+|W|HgwgQkO3@S2!GztOQdwenWcUCsUDIZ*4-p0#LkF zr`_&R7RuKP~eH2xlkRr!h_LVF9~ zW6f38WD+l6v9*YcyZ_siJ;iGiyxHHBMZ+?%E;s9Xw--&RhsK!s>-Lt~&jnx{*>;Db z4Ja3Ls9?cOgcC#jhw|d|^qpt&2#3Fun{b~kgi*@cA*h(&Wb1pMS-G_S6*@8MAv_ATL+ zVb;4n%ez?TSLN8iZmbbRnc1)!-*0pZ2DZQ9b+>}b;6njiyq9G;`o1)xY{!NLOOgu7N5m@*_ac?|&?3B0a{vB-}k$Pq4Q z=wFjj4fzw)ox=8O?x)G68QW-V*2Ksj%-Vb>@IKBxa&7PncbJI*8KGLS{YT;hSbPui z{Gpx;*f@a7rZh~49`ODz6RLjxg8kpeX|bFC1@4Art3lN`*DjdMZH%$2Rg1$tD#1Pa zlFkSgz-Q;Y!KAie|Lz>t?%@vUJrs+$!@RIDfim!ZIy`r8I|;<$1fpZdwNMi9kh)KE zmR=aEbq!&_AK~C1%cz-hUTO`ckBi%(>HHh=Ai$WobMAxJgtEfqk!~WLQK3O}5+)Lo zta9QI$~PA<`CZ`j&1(L(DYx(Z2VxL3;E~9<-+oEiJO49@?Dq$Jep2(}jXpSrtz7>^ zHq6Qa*nr^;;7*k(5;Es?n1~NA6%3^BMdC0dN|1b_xbN#*Pt1O-yWgqZtZ=<0wO2F| zI=3(iHa?*{jJF8wiVm0^011f;uER`A91*K6#OcB_FoL>Rfbp?=%J@$&MBvx|QFP=rATl=3^DgoPe@Xby-eZ=k;OCes1!zG^10k(0<*7~m6{ffv z_8}8u2A4yIfm9ssa5 zO?V2ZngS#1XFs{%cShbRlp^_K*$f#y++7w}kN1jgOFzDn4=QKCE2T^kVGKz@D?Uu9A2-D(WdD%P{PwIvAnG{=!E_d=BakY~SiwxAWl@ zZ2y*adS>h7T6ZNtRdN0ovg|M93I@W*Ryr1h*z+tE#Adm2uYRc^}7L9;t zL_1{jcdg9H{7-IOpu?6}DjW`0#^i-Y;wQ3l6erxaI{(JfT7`6C_}S+fM|zcI0)9QK za_{LPB4=N8609!WVvJO!D#Mf0c@zN87rtVS-^FhEHE6rzF3*4@-{lYcX$fyDO+@BG&lxa zY;DR&9&+owR8>Ub-|8F)F5C%u`qc{HW1Ls6&u0h=@T2U_ z+3>>{FQY(jee(0-+nZY@n2;ZNDIs(Gw*7Z2n~Rot%k8)O#Do=p3^r0=kf-WqFQ1*` z3Wgl~W^T3~%kV~9HnC1lC@x<p~ITS)?QN+8y@eEG+Z33O04Lb3_urO0_c#Y zmj-dN9kC8;awyM#F<7q?_f(L77=V3pBp4&3e=I9o4d>B#D71=5UhA|~+(LC7;O$h% zvD4DF)rHK81%b_zH4fN1D`siGrqFB2k8erP%cL-Ur-0l{U6b*Lf;lY1D)l)jfaDE{R z$Q(k1VF74G52j7u+*F7vzmC4LYSGWgy=5y2KKKBD#@A$m+E3Y>f%)_f<5|@pQNtU( zQ6C}di|5J3zyCX+u>Mw?ckCmddOFw1*em?V5u&De?+XVx5bUebcw~Q>=q(=RR-?t6 zcUzppv_nMu(qhmX!;*NJ;0|hF5&!f#sIU>*{a>Hjydh2@D0A#}5H`y9bYdIe$8*8s zNrHU9unZ*RdUP*ITW(Z? z9w;>}KKIimEQrDH!*j5<2>Gvz-(PtQSR&VskTNQpEMMrC*Cur$)=~V^0V4Q>eh8Au zr|}N2cR2kFgoE93;3xHe6*BzI6plk8U@_}1f;5kgJ)j5hzB5TYtq{CJ>=XL;xIZBD ze98;vf0|~KvpM5J&;XVugLd^=JE5lV3+CFVQfVvd=RQ#Z!cx0BU-4-}1^Hi&<=uA% zgP^BmYf?Gw5cG#_<^V`F687-zF4qx)hmh@H-`YkDk_jy(E{F)xPuxv3u|JrsU^G}7 zHU(YSni`JVc(~H$hcNQ6w|%Hb&Rt0v%YeLDv36=lfEWKz*d9_>sl@=AyUIaN&XxZ7SiR-FP)?*R`4SvVI z?&VhJV+;9+vaQeVC3K$ceOzqt)O>VtE{5JKT(F{I$DgY_2OEsVIQvxM4Hsvs`YXCt ze!j3^6qYZ2W7&wHBrVVMLA|;+kY2Qe&xQ=R?|sstN&jd}(wZTwg{{BhPSekzP<(uWpa5>ZYEgnYu`zgRD}w^ zlF3Vo9o{<_ZoX)adr3)%ZIJd!xywUTtE`;vTe25LX4aH9(R0Z6Lx*|WtNz*c-H{ z1OuJ0-7i5Dw|Ib=WuS{6#w$zM8ByrEVDZg3_V^bqw_kRVYD$U7jz z0|_-KW3Cfr)6!p1`Oi0Yo>*$~kJV8Vpy6PzW+~0nijoWT{|kr~q^Wc;PYMJ}GLenW zJAYR3#FME_%$SM!(8EYBMNB8kXjEjTee>fQjA~<+4Dl;s`j9YADs##OL<_8-tQ~nnu)+YZS+< z$C~teX>okKY9|Xk2HG0+sb6$UlIWau+u(KiXNsS?Scm|-e(Li_Rmwg&-*NR?Nsitj z_e;UiOhQ5yG<+WsVMFr<>* z+0jt2WlSpkSAc#{#WY^-RL#@`@^IT;`&6G1-Q=^03L34(KQWTz#-s?1itPCdLh)F0 z`T0fx(jfF%fEmp_I04Ns&}KP7%d5W6uR+RUKAqJ9P^QG1Sx4xN>UD3fVk??fy*%a3 zZjNlNI@j5(oC6mkCv6+n%k7HWIkqleEOHN&TW&Q*1=VU=v;rVOt;j-}l6}6*D(*rO z0aI>&}AJBvYqPnzW07)4pGKWT*Joxa{7;fOr9+S4mGl1@Q*kxj8bS zsl%WK$;qSmQ(RC-pJ?HHT1;3v;(V@BX7Do&0(#H(>A#sB8zO5y8Uz{sHa$dk2U+x8 zrS}y9fy58bTa{4~BcGNMH=~o^fhQf$*ht+5?R9oE?W)w0l_cHQo<7+e#aHlnE*Ujs zv%kD?Z`m*d#z)T>HHua0?nO1lz`dki&!sn8oO8AQe`nfS9?I=$mzo}12`X1EA6kn- zuKRcNUf58>#DqpcN^xwZTe|>lBpxJ3Nnr~&l}mm_&dg9%iQx;N3C(bI|7pHJLSoE- zp@CdbXSZzMC9|+x<>vIz*TGlpcLt0v4*Qv%#tsU1m(Hc2EUwIvv@%e?N6iT}I2^3+HpOlhSHQ^Jp___R6m+AN51OnuD^AHDti-CAKG zz%a8=N!~FVc>6)tD0TYdWK;wpZ{0bjLpq~Ynx6H!!2!zqty!doA;+mDf+Xnv)jo6yk*O z@YXs!HB_OJee&g%dqG@C{LcNS8Eyf!-MM3j(-!K5+xf41uPB^=ksSPY>7xK20BE~{Nhc1Mj_ zgsO_wazom4UV60z2e~ZsH6zoMiDXqph4;w1Kewk;cEnC@|Rp^vb$ z8!TI=EfyDo19?s0FAODfkj9wHp5B>mta|(c>=lDOC9Z9m>^#y-yI#DTXA3T1ewX#x zz6BSDqeXIn!~$2#|bFgH|BI;^0duw8cV!z1YEbMEt0HN1l7J z;J|>sC(ckuMPk-jU{R{}vySN{?FBTX4-4^=z)o+srb=6)g=!zDK#&1%uJr-_>Ts@d zM}8!^Eq;H(gK86ZFUJS>yUQ|s zT3$BU9v7TErPex`K!yNH_YDi0I`r;P;%E4ECLY zwnWF5=arcSM8X1G6(!e^q(HDn9E<&|zwG0mFar#`8M)N`15&5AYGa(Vf+Mo-EG9LF zaT9jN#XOVzN;a<`&8N|6R2ils!tCGb>uzcE9;RlIbX}Az~yZrCIPA7#Z$UC>aI3Ea$Vru_0 zF7pczM~lgCA;hhL1Z+Z{D)wOi8_LveJ$U6D`HU~H^q9keL_A%}fGA#jvi@t=q;I;i z+swW9ug|dis*x=?tFrl3Y%l&3))$!ObjNxw0e8~TbW@xQvlZfdF!~}ci=1CpM-&eP zXy^sExu&Zxz-?JoFZ(oAhr_FQkx{L*=0nZ22Yh|M4GxFqwk`fuMx7`Z4F|U5W%u_; zJmzr~?PFSM(-tT+x+Q>88$v36do6eQY52&BJZR4iDEae+_QpB<%4g=)T@tSWqF9Qf zP$KrHQVwv!79S}j#l9b2`y=bsUUsR4^z5JGG~k_)B_q0of5{5vT+)Y3KX(fd^dkPT z$)tmBPH^a0p={=A?O|N=Pv_+P)k}3Ly*bT4D9SvkhkJhkI4nmcv2EEK_I8Kk^M)>Y z%Pn1loFH+)ByEKfPdNP1yL9|=YtOTTCDQeIBrvXKIJ)RcvX=O*6|SV&=kU1?F@+%ZOM={N zQ&~%i)gR-Q=w07^=dQ=qeVduG^u^@ArP>8}BhBN7S=TC?s4te3cQoamNJ_R0EzfSJ z>asE;J&5ENK;)-i6;M^*W^dU2 z%J+7iRg^IZ(A03C5w&+;KN=ow*KKx3R<7P&X@7T})@6b~6FToNt>@f1^W|W8DRlYT zHJV2?&!vjnNy}5do$BRNYf(CoyC<@2(85`{!hr`ne!tI0R7i=8Fx0-pU1UC=x;{R* zXc7BWa7~_EQ5NADKCW5uvuWFzK&ddYr*fO_fw$0K`S>PI>+sB#hU`ed8Gcngcx0 z(oerwb`BC!f=_Xe%v2j5{BH!&tdIC_GWcL|QdS$|C+@LwAs*KW`v$ zVX0cvn_M6G=nuwuA6T7ss(R-80`#*~ZG?r$u(O>?JZTE71EFLP#J~Bwbb_xo2MfSL zG|_TXp;emqS(Tlbpe|Ta`BroJQIdSM@>;*334elyJj}O6sw$|m&p*p4&mBR8LX9%* zFs?Q2pa4I@h9Xqq-GF@KpNw>VU&jH(ZTBimy{u~)X5YL)cyNJy%~Wa)UTfb9Q$nrv z<5`ourp4ZleAP$MC68zlPsFU_aFFM1KLOMjTLs?(^1wF$O-W4*dgNEDk+=vdx0)qr zCRlyI_jqV2ldDK8Tg{RjR)oGK?};k@>5Zo=GCDsY6`o;QEcVVgQu7xvEW%G;ml|iz z78Kk8Q25CW!Cf1%>}iaXqz;35*5!h(p1xNs_=C68f~MgQLGl_stEorZ>-Y)!uWY%8 z9(gx*XM@f|z5!306*23|#IiBo3 zs@Au2`O9Vg(DPCceLKx(pkomQe|@{zZCh4s{XEcjf{frB5p6PxPy4`V*A;Bq9%1+( z)*-x{%;Gr(eDH|a!Wx@}UZmojUhwf0r93wfmW30_UtYIkGul%8_8q}uFd^IVKal8p zbDk_!6pW!R5TmM)D!qocE+ozOUMV`W80GwtC_OH3z2Ehvo@Re=WWhSluUKoM9>inV(p3E2nFaRgIkWJ?M8frv8ukfxTZ^QBdgbj8<|I7)&ffPKi+tVJRPe0q zcN|bwtk}rUi(KL5T0AytJ=e0+X3camZiA~kCOMc+i$SWR;ieCmQtQOia1XqSWhhdOYQ_^F~zh~Oa0NT=9l9a zRDzHCm#$@OE2=S#4G+ymhmCEifB9ff=%#|W#lFeh)cuLo}#SdX6hi&|gS zdh(R%&k--hRlhki>UDuGvEB*2-gWB#$ZinSoQ~#W%$+fphVP*H{@MqlZXAj{|Il+@ zJumJQMVs`6kInbC!B}KZbrHQ`e`i5+J?c(y9LqNnljcMq0u?)!)3|+his|Ncg4|r* zpRdDn!B;*x^LQgV1h8Dqa0!%rpzYG}-n7noeUbXSLFE=9uqHJs_p+{KSGDHxGP|41 zlzc2N9THQQZ#OS(a(=924@x%rkbZjg&nqAw51!w{{M@`(IsYvNviwDOoTiN~VM~Yf zoY?~(Ja-_{GY+k-IsY0-hbtZ7q`BJ#Oc348*~a*Igm0!Yr~}Kt@Bdi9oA>rPv{BV~ zV9)a6Q@dP-Q{UTMh@rQ_t|b7v0FA-h@IQ_GK>~_@xdwO`iR;TMkq_|;Tvz(K+)3?R zXkiNq^R)lS%{S>mDW{@WKZLm!Ik5FTO+Ey$5qp;YG5^#=bo98g~L3# zLCp)TQXjuH#+uJ_AHq~F5Am+5>^L$}A>VNpG5t=|F5-&ul{oeeTzo8PtB)6J*obC+ zA{ZZ=r7?X5a)=!JPZNyMSO%Z0I<`|!zVP-2^O zMeH&+->FM&=xr(;Z*ZU!h5u--dmr1icZW0<+WgG64sM%$j+RQI^J*S7T~7;=;9uS3^2-IcsuaP5OK>WNyis&;yjIvF$?U zWaU(tPBQVZ9!oJul4rHF?5qo}t=L^qn^&3^dGaSK!EtaJ70GExG)hAgme1~qU*r^Y z_hMX7m2iQZ)%sI4{eNOp*s>wqA55gsW$Dv3dh^%rFSVR|^>7ANvB_Zabdw5OPaHf+us^?WK*#PGtW1WEQiY7)AX-7G6=eQPci< zvpBDBXcG9Doa3PJ2VH3twI?-SJ%@~)y!wO3WocROCkR}HN6yfQ5NYp!;cV>kM8K50 znc{WdJ=kNQPQw7qO!&bTVl)1O3MEz^kHjzdB-q**P6IDm%Q7nbNd!kx-mFIz6Wk0l z?H|0@$2wNBZV7hH$5qS(b^wK^M_JIxtcCS?H+lRqWS?-%DThJdNRlwcWdG)HZEPp) z@c|HOqG@QS=EKwpJ6z>-K0Ys2svkl?>0X#$%rjgrxGh`eR$DLMa1BJ2>Wjc5*T4-E zY8gwQ5%j>(cTfS*b_1;y1W0oQIxGoFi4kCB*gpUi0H?~VB@KLd(PDc`nB*I3-1Ut&@TrWvZ;#bfe6kt@4;1 z=93lb$s_2M(T$%c8E5$f^~Wk&d2?n-^#mQqm>c(*9*Yje=cUCcYjrdmrOx;ISF1dj7(0_j{9hh zxC9f|>rJ#Pu-?a|4q{OeT~d9uJX-yz%y_1b=J-?(t=N%eO9#qE8gwqO1rQmW?|H9p zkdC|a95vXoXf@jES_q5C8raLzA|sLQVT3ESmDi{f@RG_hBn#lBwQr+a`S^V~RUDT=j@4bIT5xbX8MoZ=?WfPr zG{!!%PM7LR-KD>o>INauTLlik{uV|knj1*^Na)@ZRD1uc^i`t*{--uG_k237yt+&= zqS)G1SD;sPX_gWF)H9$14&|(&3$o+YICUovhSZZFG*<*CNQD15xFI z{piGDSD8v4OARlHeVfwx11K3mJC;cI@Q^UC&q;C^2~rI%iFV9tSckMkJM+?xSC*{5 zPfuA7Flc+F#j6vgGqVh zMJrZh57VB~baEeh&;`SRaCWx4@Dok%+aiQuh3fUZ(9}91M@UFTtYOWuRtLKyE2l_n zQl;NqM}Icm)j7Pq+;H(6re(;@RAM(2gwf}s+iw&xug9wJq~r|_rROo)>cutk$GN~R zAi%)dP|>9OSOo9UPkh|A=o(!=rLU!-QE2VL34GI}YXY&p-0=d{*YYiyg*bZ#CX4Y` zOBD5y&`iHFJ(qrD2Un3*)ItZjaLu)H4nZ3L#5kZDV{6_u7D13i21uAB4Xh^>3Zw5Y`l`KK%GBFR#Gha8vY|a50!}3BGg`otV9Hw;M1G zfm{IxA^8~E5P7`g(fgMVd!>B(xMxKB^h+MA_7rcxX?w&8w%YN7AP4dqoeJ_p=Oz(v zz0WT#82%`MC!+UBD6Z`DhRGyQ9V6>UJf!E}hu)!Vt+R@5n55cb*64YpL!R(<(Myy}vMzGv`?j2rCfmU+?kCnbV3GdGK_j%4LA8bQ-5 zImw_a&@l%+@9V|B0abt7~HXyBY6ye;r=`6d!TcuP^!wgs$fXdZ!2iXY(lVI3OFn9v6*@AyR^sw80U=6|5o*JdZ40Nwo zD+lg-c$&KL7DbTB7PHeP^8g<4N3~mE^55tC`x$lY?~^yaa&TyRxtL%>J5U(VW!jtY zpo}+7m>=h&Lp7_3b)q>NeI@e9SBIsi&PQWvJijs*b@pkSc7+(a>sXH(#DJwyr#m$B zWbN_6=Qy#?q^x3J3T1lm2$u~~fSAghpu-ihA6!pqh{muxG%}eW5_sr8i#dn^1#;pV z`E7>;z2Q6i!}duD>oFq01LE|XTo{MCWGsnZUTBJeFp-AoH?SzCC_&pS12Q6$j(LJJ z7UFVybWxhE!TNWTb)RpS2Qp~hLBQU7XRmJU_SrOIC1}-7VFl(TyMNlHn`1V9e}?K$ zy3i&PGzR=$eE0^h(JfdHPz8Id5^(7H;Pro2xu2JJs-u08ikF7Hnkw5vGTxzGiawn5 zYTPKkUX@>PRFklM`e2GF+`vBe_HpKM3AS`}qXIa9J?@}swrbWanfw>gb$Z!$9FCxB zcEtwSWM0~?20@{`2*)u3Pub-5Q2tHS{jq1uMz=00BEn_OjdsITN`-1MPvgiUng!Iq z%y`&M2OI(7rs)IB^Efl#Z}xuEq>O_Sp7bY|zlR6XV4P^s&+esX<7NB^eOw#U3krs0 z!nf;Nljro&tl2()!gM5Wvq)kKGZY8>6EMJoD^>nf1YW}XZnt~y3-N^&A&2(2IWK|o zjd2eDXVGf)+LR*oRqS;+LGX;o-MCfC znH-nfjMRlX!42r66)P2Hqma^iM-J_Mw>!{$@4?C-k&a-Xw}2Ng$SePhGOJvHvf!ku zDd?7jd|#a%YUVL~jr!anUDjArAg}xkF(uRQlb`nR1$2cqs`ZI2zdT8Koh9kk zT#cDp2$r5=uh-qbIpy5I_-WF`^u+zO*p!XVT$0yhM{^SLjXP7H@Cqj&`DHI2lFBLG zyUmIW;O=EeT4fx5C^_Ue z|42s*tnOawdRwj?6e|66_BJz}njx7Z_3d4oBg~LHY<7|-NpOxxdU>Q4Fy!QwM7FnG z>TVhe7G%^?@fpnCQnu4*}2mnv9s?TJ6v_^-98_*dMK&!^jQyN)!koF1r_^!rqlUx)41t4RbQbTohQ8b%VAS z=Q98)AgkWPg!FPpn;1W#nmNbZ3UMa%7)(2iY)(A8=AYom$7ic7pwE|i<`?`)FR zBn>bF+3lu9)GP7v^Mf~HY5I5CGgU5%+SNQ0w>p8XoeKQA@J{L5?ElXnPEWPMq{}8r zCrp;2@`T>A*PC;HRKCGci|UVCGu=|n+&ZbxR8SWozN?E@r_)lM+c@My=gSU){pNh4 zP7o*FW!gOl?b2z-udm0al#mbU$O?_J6rbNq$@GDzD`R#a4m& zd@yGxAMxy~QAgmdD4F&eRxy|JT`MjP+CCGR!-hWiO4!;l7f<`u#fF8!a}mkB3?=qE z()hZZRhk7;5j_qzDzczI7Iu4qe)7CmAA1TM(u|2qmn7s9GXx|DkeJV|z536tyk48k z`1qakR+6%=Y0F==@W$x?RATv2geaMPP9uG#CC{0;afUo((2s z%Vrfq)Vg@k4~@W|E|^qx2=A*tr&)ueD$N^ob}dwwsvBW!elP8!d{4GMX;lZu<-(!4 zL<(;MbIKe8WkF?(TE?M;ZzO8{;Cz~QJPXjaQpkwN=J>(Y=`r4feRq#lmI?FKKDMQF%9v^?X&EIi0 zLWPaC)f*@UFhcNPN?t3-vk&JMK$1a+N??#(6bL>uw>SAjg1`ChZWdlJHy3rX zx!DEYO2-(Bc4il!oHmqAU>xG-NUt0~NjJ(<1mTW|O4Y=F=;~t0o_8qF*ts=6xO@Nh zu+&FZ#Liy#9=g$XkWh=Upr}y>5T&b&THM({n@h}flg<*zuX>BNyqRy$%Glfq&-j<3 zntaV=A3Y_xrepVBU|yTc1wh4kjJFIxks+F`4t0z@{JL7$@)6BU;L_Ra<+s5hOb~7P5U~l5k`R{2pM9~#{|~3EJ1ENDe?uB}*t}WG@e4^u zeRI~jn{R(Wly`f%>$un24#T0qKFzNq<6ZPA7$anl8sZ;Q_>Dz!7?+UAkcNW^dCvmhn`9QnC%s8!j(b z5WS6--fQ^jLh?xY^+FS}w!DL3(dlwLvGeBz+xT4YLo!gm&&bpqmTu}RNXBi{kKA8P zR+sMrc*YfgXW)#p2)p)bJxy-B{wXTXW07d7T#FaT|OG~K06|r$u=XrG&eF^H=l#4teNWH+1J*=haPwI{L7_w|la1y*zC1X=cUX zE!|a(OSn~c9u0(1W`SlFNnl3^BBu~ z#|NM=7;x1x`3HtiWby>DLQWGYhRrtY-0v0Xx`A0rYol~@9_@l3HIITdBQ<2kc({dzaM3{T2ev!9 z4;(_;{Xii&*7_^6a!~hBYT2O$v)%@%@GYz?jY9S#VXo@xzFgN>mfNKe3S+W9_?OFFz*w7?n!z(5_Bmb1jN}8rbKFLVN10)tnW7 ze)@}qrRWDsr`YJYOILqzL64&INg2NP3|mJWI7bNZKJrUa#vl9?4GXtekwnT7FX-cs z!Ef(7W;{MySzQ2mc#R(HBa59)Ybkr(C6!u+K$+C2 z0olPFnIvkU=jA6M3W@r=E$H@o+{}85gVLZvL1wF%WeIjY$St8I^ij0KV$3*p}?%!Cx?HO>Q z5$>@p;BF|$2HD;2fS!C+I$BP^JaaQ%&E`mBdIj%i{vukP@jcpkqj#D`HEdzR)CN)% z;`}FxQwp3`ML`W;aN6VM`cAJewh=ZWt;;+t@|Z5rTv>w_h`-tS%uEjkU4~AeS|hv( z(8u)Z16_H#FYQ+sO+*Y5WncpI@_D2F5vCmEsd>XofERH=C*xYpQ|a=pQCg0RcleZRv>#G)A>2gopxSsjS_pd@DT}X{KC$vK5xzWcerXn9_+=< z-TGbit91}DKg;^G#e|Xt=qo2*pH8;6cc3`jpV+ZzaxwGqm`@T$1Ow)qGX*XFMme@) zI-8!&%e7q{n(mug>!>#&d>!apG_ZH{9^dBL)bQw7`mKq1c2{`j$4EvbRDJ-ToqRQ% zN{mpSbzj4Q2AF+>@#QhD2X&#N!S@@OsI!B4<;R5=@)%Z~kkw5|8pyvI2XCu5eykQK z4=bv8l1t}HoC0zMmEi{KL95v8EuFnrY)CU5^sdhQsJ`fGbv^RS@1HeAta=YG3w8%> zmHRMs&7yTTNl^Q;D=lqRm4xdv`6ZSq$<29lOw!-EbhS=#ycx zb6YmrWVf@$iV@3Q24FP zoV2V)8qDGJ{w5>b{IkG^%`dXP*e}2*Mr|JsmY^Gn#-Tgp3roY*FWSp$`eI*UdPI#Lgu^KVhbI^a80Ald+4%35<$PP@ z?eIk!1wyvNZ?C0u;C+H26~`oKzVx3KyWFyy4emKESRPQ6njZWSt~k3W23>7&Zg969 zJl*SnvzId9q7!clw5w061ZL4s67*Ym1h8ExLv2P+uEqo2ekFJhsyMe-uCptThr~Nj z1owybU#vIBgV@iewv#R0mh)dBQ+u2Ic>>ryKnM4CNomtbF`Z8PBA#HGWrRw&=K31J zXCFe)yc0C=jda8f^@ZgDKjxeQ!e5^`P=zyKe@KzfFNPlHbR3y6?};&m6Y66l;*my& zpO>lQZ-yu<0%`~_4PlCgZ`z5DoyIMrlptTwA&Iw3P^9|9Ewb+Y##^W?Uv6GPBAvf* z90#LOlN;6HzuLd+=<|WrsPsC@e5Zg08|37fV~Y@HGVFJ1Qjoy z%Q_7|S;zltySQ3DynFG?@Vty(chIBsB)WOlSqSA@R%WhP%P-Y#E9BE`R;s=+FScf*lE7My??jF&iVfmbPL;v4dApA^) zf>pCMh%VvD`amd^p9kMPcV-ibU>FdTUw@1?4f`xKe-Tm|3R<6o0wf>m=x{_zR~5-srnrb@ z{Sabc+9qRRRQf{`xsi~#dRc4a&xJ>wx4YafVv-F$oj`u1x#vx4=d*j}g*a zrR-S-MczP>6*Ou|G`(18ahkdEukiuomp3SDep%vKy1pc^Fz}O+7P7DCX3i=qBp$zj z(})HS6k6coRGQ(czr})X$Hl8Yn!PtJ8@EU>smtHKkLHUW#6mtk2n9d_=q?20xKqwM z#B0~Q1{d3mdEhM=55={ZTR|!UBzr**Gtxhv>|1lY~>=?P+EF z_ry7zt0lTi$MJWu#|q~vJO6_F3yK{m6;!@;LQ`3{Ciky*&u(6iJ64o@t{t-z;|qeO zh`RG$MnQdjX!yFlA-<7Kl`aM%K?~rNwIk8z_~uEObbsR`|Ei>3|(W9YqzhA?iG&~ON5EeK5l3v=r>c{*A78Y-^h>BMPYz@qHs{=A7K2JUBbH`TXG|Oy17&RJ}WJBkTS7g4cN4PJ*sb`-ga5$L{dh(jyD& zv=hz-JP{3kVhlOgkbd+V_BKCr04woc)F0Hs`>~iLkdSa`_^T-rav>N(gbH|S2Ait= zD%Tjh+!ypA=+J&?A4~8r!t_N#6{%!bbg}tK9DGp$q!@pN8bq8TK8){9FO8@>w2ykZhLlW(cagvDlup5Bm8bh?sGLygQW*JSEybrL7#i z5L>rf!k<&Vf%N$Z54EICY(}!|VPC2EWV`h`ryGpGKF)qT4$Gxh&({2@zGc(_4bSVs zk}bQXx*(X~Ak^}EZb}?}EN7a-6?y4R{$X0qhRo6@jNdr1MT?bDKt97E*pC^KxRZ^@ z^b-J#6#s@K{tz!K8sYh9*2HH2kTW(9a&5g`{T(txDp<(G6*d#?lDHEsFTB@ah+0Tt z4^OZ7ldF_I5?_;czFWYB?i*#oS{^kluoFR2wlQYBJ)~uX34aV zdtqB-B&+B5@0$vZbQ>S^-8qz^>a+94sMO{i2;Di_8!wxacCw`BGjhy`M%b}$P|555 zh&2_*&|?kURyLev0}2@BQMx<2YRd~BJu|H*m9n9!1{ zuLIR6IgH-l1f4ajr2oUzJ4V;_zR}ug+}L)~n2puAL1Q;*Y};t;G`4NqwrwYkZT4OJ z_dn+y=X*y+ce2-d?t9K_&gTUCG5aCL)$TXD!4p|)7xZunQSsV7(``%33WfB|B)3_W zLo6bTQ>rq<7CtAx0B|uOD(?fH4pz%fn6(P;EqEeo<=ak3UOq-2oKBxz(pTFu!lUjfC-IaQEj$?lHNR%&-XtF zkmdGgNw0&oKK-uZ;@YXk10)rxrUE+3&(be&@9JyGH(eqO6;(Tq zySxf!zUlX2BbyQDH%{<3KVipd+3CBHL!n>8U^l3; z3lv82!PlPU*n+fZI%5<)IDn(FOQoYk0=J^tdg!?{P>^o>?l1f`PX&@7zkETmrX@Iy zm->z#ETi>o^mvi=Yky-@?B~80k!ZSXu~NrDC6K(cEYwtJ7~%MvUW; z2&YwhbHA+Jv^oWHJ2J&9O_A_pV=yu6!Co+_IlWmr;TRxmSm|W2{d3!1aD62%-SuXBfxJ*pE4Yztc z)GV!@wcK8Dv`4-b)Kqpe8+Vactbug{3TcoseuDJ`*G{Zx5RgjU&iP;^Sa4=bhn;}0 zkf0Kr))0BQwA{TH4?_1Av! zWUolSWwR698To8OBK)sPl@J;QGl8naD%`{fX#F~y#vR0BLw_m;{;J5`Pg{g+ykp@7 z^zhZ-5CyB=)l(e4*PCCG9Exa@5@EiAj%h@=3Y#a5QbxSKRr`loyCucl` zsL3G@*`kg40W@Q7)19_xoO}$DsqVs|qP5|{Xy*@Wk_bg%UE4;-Jk~P-I+GA2Mw%<# zggDs%pCm%aJw@yMbZZJ7A+$c*fTtf1-+_5Pw2NMy=t`FYSvQ#XyADKr7(#r~&4tGI z-x{BcEyE(4q{mKt29R5C5?bVW@|SK4|I{|oqL$I3{(!`BAd<|Igp8>}%{zc% z9w3uZz5UZW$tKHF0H{51O%YhB>&X147X=UDwl_iTdOoAHC;aqL@_4)NIg3c zD=d6x)Vr?OXw&>Te7v|y#w-_WL2Nf&HD98jCSe4ygIds)$R6Rtz7{WQFdFfbocTb9 zin0J2;dWSXF+LzHAEHDbQy|^BIqxw~L}VxV-|4}aStQ&B+8e*K*<2Jnh@b&%QzCio z#ISY=$O6^1^o7{#u_aM|`xCQGQevN>*#FipJ<(#%TmljFJMPg&H|QU?fT~j1Kk|qP zZF-w9&wGmLCboSA2H&5|1Fk1Z{LJC*1>TD&}^ zOK>4WGRqc8e^H|g*{rRQ6E+wUTJ3d7+}e#*e()X@N^jlERbARRNM=jpKijH%>(jAOdc=W7Lj$hrkV$Bf9G2>Vjog|A5`s6v>oXnW zGD|Dx&K~+pkr)2BgPEU6^vOQS=Kk7f`y95#b5L7zBlph#$I8(P&}YJ%XG5WQY#I29 zuH@2u-g!T( zuy1Lwu2>9N1YpMjj}Z-k8jV~0$JKITg)*SGP$pjb*&aEVh&0?+P(smh(mN~%DT4sS z;S(XXv5!Qtg0$t%3+CZlaaiauMJ($NAR4&CEqWqYJ?Y#?Rk$r6d_4D?pgtB2C*8l| z`&JcK9-TUsTONpQ1X!=~a2S850;@}$CB$ea6Ctz(yc;d%mJcgoPv#NcA4`u6%PHj7 z{&4F`3|mT%w=e)DW6^nxziAQj*gDxQ@{tf#CpDK?LDeQEB5!v7dprU>_nX-bhrW>4jqFE&a+ttk#)x#{bd?UyZx=rGmGpkBl_{ zLPt$&Mr$%QjwK-!csGO=p)q>Y68Uf|3lW(qA47h6b(x;*zIFVL1-=;tcg%%DejQ0A@0f~l9>SnJBb$tZpXAUL!f>s}W!yi=jur=Y z%5(N-I>!@ItKMZ`N0P*409UIYxT`eM^MK5`)J-=D15lCNLKqa%o_IiS+EsdUqSzjD zBKMta51d&43*vjZ*3mAD&7?yI?+NC}p4-JzmMCKwR^8VIb@QFoZ|PLW<4R}F-WC&k zW;I!1<)uVBbpgMR;P%W=SmE=mCeW#h8Q$oycf^7uOe}+`ZmBv!#9~No&@Oaa@z*{7Se6d%5!AA#*0p;qj`sB?@=&miIzXc|=hFZvg7DYE?<6oJ&TDb4EtK z)ICf$=D4A1YzJdNn+&kE#th(gP*e7(F9~i>SavanVz|$(savDik&hwXHSj)s^_DTW z?DGc>011v?&FYe$MZO$~7{MxE>ZySDHikX$#>l*893`(^@*zZ@^KnHUtti!4+1YW- zhR`lGnVP26662f?JP)X=xQSNjO>q*+E5x~AF2kSrDqSMcn4_+l>oW|ibFyHDQ5xcJ#U8Q*rh zr#pto^vNcJRi4==3_iRZi{)N*=UHopPuc4;`J|Z6(JoVjQ_b+ zljQS$g7HKQzDIo|DdV*$QbV{*hh-Qac+il|X@lK;B9wGKb(5MLb|Ix4%z52RE1p&) z@vEm}@BlWC?Cd`D=wyJZg>^P`a={MMiGlPW$P;*wuVfm#+})$5)BXubS-d6VSR~~> zG{-hbHYV{~{NPUJ^%N#bFBz+}LNOhg&1I8wj`Fl!(&<2JWgcUlyqZ>NSo3_P5cE*m_YEiV6bq3=Sw~?y51qAfD zS!>kHMi8Q(gxJl#*R%(oUP?}BHMo#nqNk6sW?-ezxh-_n+H7XI*;NgB{2PV$SbX}| zQXlN)t3&tdniJV1?@kj{Q!zHFWy*PpOAcV3tA9r7~KM=6o z-F|VMfxsR-%!?WI1Bm#L9CP)S@(P4gnM~^q7M*koW-gDP{SG1TFYdK@V%8_Z zh$&r@$2Kvq(@$t6Fy>UxW;JZainrXGhnHsIT-8k8@&kT13m(3HQDg|RL) z7IdU|yO>k%oeIWXyNeV`)x!vZ!lxTysM7QiK>D7&2)W7MUI_5E_1V507gL9nGVIqb zt_s)8>^a3$9!`ifLPC8)s4SG{liI)l=s*~=Ujk+!jzoKv64R-E^&%>=!peG@A_@4g z8p!ilXV&kY9=2!KA^JGK8tnUdI9Koijq{5jJcFzFX`DNx={lZE#H71S|7mBMLEPlG zGwa#Pw7i>H!@I~HyUsiL2 zLqzlav#B&8Lol3zm>aLuLmXB;==VW7KfC{@jDGv5Kx!yoc?Fx#Oj(HwZ#RFPnR`hQ zDxKx|L^hBB879c&7aa>6QbdIWncw7fU26rP?IsbJ=`09W;SH4fSOmUm)mCa|`9?m(kdtu69RZE_LIlr*k!um;#! zyf_148i+7QoGA5VB|BLU58#qHV7NI!38PZCRu&_jPbUOUoHF-G3#gSSxJylD6Zg6G z1yo2oNdGc1%qfy9--mVkHf1RcXuYlq5&YOIARzZ(r}$g=pa}^*k{9sfzf^_AzyE3~ zE&GfHnAG;7Xf7*jAg*ncmzqbO`E(<<-7~syE#pD2eSB$aBBKd#EWBbG!sGDhR59`I z{7yLDq>I+$E`m-bZ`wRx_g`^m_gcr^Mmk-0-lCwv_9$t*Dmbc*mpU-E39EhjH3X8DF(AYlG==)kd(iY-FG=Rq*B&X7oz?pD3V$= z{zQS^Lsx_*%JA6-$gL;ED$8(IABy8ZtKDPBkhGHV=(PI0#36p-7487+QwB^R?o`(e`4{GLx&jCnw$2p?Sjv6*p_1{lVh7H%sPE zC?M*v3EDx95IWV2@6LBPw%K^qakY#trX8F=>~D;|M*o%j&1tu)^^LLC&&;0XGR)`? zX_u>%UrANujf2I@)+W~45o?WL04S6(E=+WIT-!K@1Z9fpY--hJhrdh z9R^tp8$ZP)NC3jp3y2PZd%r0c(VU$?zIl7M$_85xN>D9$oK)hHH=Hsm zc<(_!O%{asiEy!faSd}k$4VIxsfRcu1UN7W4D*yd9{m%WeexI(3MRm^!)`Dm@+B^NGr4$lQM2YzIP)%~@1 z%qG)s`+2E;Nk;`OV??RSNDZ3Fqf&){|GD}#sPKtgUvVS}md~v}t?hwf*xffdl~d|< zFF(Le0*MrE?8(2bh>m= z<{H49^d&C-68switn2$^+Yb9&>vWMeu3q5V^r?rz!Cr@U;sAf;3WN{}Db64Co6nbu zz|tMfR9##Q3td)x)XurQr_k{Gz2b?|DMF>1P#S=w!-KKzYlippl`6O3Yc+3J0WLbz zrU9d2MV7rTlDFquAFlw%%dO{nsxb~$iXMj9YxUl8?;kja*6O^kK!huAbw(F$WG+*b zbl#MjOoa8J&LycUgO%64g+Xy!?5B~-rq0jS&Gx^WkAGL(pSRgL>$w0`fTOkSEa!r z2%Mp%;-)Shr;28BP%-)+_uC(Y6ExLV881Duk z(SbPb+A6Y&7a%xA;Xg}F{RO9K)5xv@afK;sxn7(FMfmo^q&zmX+3 zf$ecnm5o9VvhO;`&c*y#TvRR4m%gw z@j1`INgf5*+h;Or%)+?x%2MG+ctH+sD>)WB_I|MiWp+Z+c zV7=~{-d_NFEPfJ#x+rO?27;4D?w1>#a|@jdr(gLyXdWG<_cW`@7}eBlHmYQfqC+uG z#W>_IH%?gA(wV!P))|Q(M&~LeQ#`I2kSbB+&^R%+g3c5>|K->^U0#cE!CQ5Fdi=zt z2;AHPOrS}*5yN%Q(tj|3E6G|q-Udal*R6dHW!#YE%Fb_slqfkLi~FeqcB=VkWvaJj zh4!dtRf3!3#7xhA6AAIACG07xa95HNelo0Bm_Z(EgOaai7HyVXy2WT#=NMa9DsTDo z5|SiTy;EI_TyC3l_6{1vv7zV5CZdoQwVYSjsrhRE)*`Old=p^!XAJ=+W9SA%kB%;X zaOmJ)ZE4d$*0%duy&BjbjEL08XgMJiD@^8$en72;g)@J*vq;2H4_FZ@wZdjr?3?^A z{#q_iuP^Yb2w|E_8eWp4=@Su^>xPrq4?H$ORm51e-?tIs(ekoo3!K6Jw4%n(&MIJ! zcnqiVIRQpjMZD|DgVx>ZFY;cW9-zV`=T!C~5yTD56pO*I@~FeqX+Pb3xcDsA1}l2M zzMksDO#ZOJEPL$F?uECxT=`=o)-;L8nBF=+s0J&8nxW6YYah_(`cK^9+@=RR!OW!D_7g{j(|sa`JBd@^*aN`f~*F&3Pj4-*j_p8cLuhV3Lb`7Tv^g zaaq{203>j^4>w&6E>ICFEu8;DiuGPH!>-d&-QvVI5Nu38(ArPq7$06%mnYTfqH;{? z$&n>qE|dkk)LG%YoN8}gGHCyO5a@Mq{_ht@$kz9p9`sC1! zLb<33(k$XHp8#((V#AE`rr|lapG-$N-61{IY@-cpMzY+r$dU}~2GK0-Q^}iLh zSJI69_gL>7{p#_rotWBe^zF75KgZ;Wka1*cI*l0qE0V`;dOutGbA?!4fITR;dK`FzGb6zhiXqkz z#0J55M1&a|gaLhc`kiUwv0OLf%n0;VUqlTz*Z8W=Zbf{LH9%70B!!l6o$g6I>-;_y zq5W+E`n~lTtHk18-9H|IEVk&i+!H@N0iJ5oD1wW&0MVR)%+IXAnB^Mg~jm_!c=<$#OY#%DmlOdBT@Jp3ouF;+Q0c|jM zI?(e-Zg~05x*_3Zi3tfC*Iq~V+lkJ6yqW;O-nO&MpEI|&bbuLp$#ahLZt0Ka3V-*h z9Jjc@SHs(w_lX|$l@!jH z=Qk>H{3q1Fo#ec>>_j$E9<+nuT~)G4v#e>(YGVx;XQ&s91X%M)0ZO9^Yj6G5WFC)y zwxIa%g2LN}lM~?e4`kE3ffTfU&tdS}oE&Ci^`}3iTVRORM#^;98?PVUa>RSoo9^v^o>}?Odry-*sF~V*me9Mi8XX+0kRC(+FnXx zl|R1llP-p1%FH1wCIB9S787^Y!Jr4F#;0wVbJoRALWw5ASrT`233KnWLImOWKYdasb1K=?b7u3c-)^of-B*m69hrDQ_Nn+OEF3i z<;<%|(AL3l#EXH)xLv2RvQB@E?8d?}IcGDM3R3+%$xhAspUx&@o(jp*kTJNC@m(*H z6#Ft+JG9~&A@Cdjsbor(1Zq0yr%&y_;n5NqM(D3-$Yl3UT)45T)7o735aY116!sDZ z0B<_?MU*W&h5^wrLN=s{#~ursR0=pee*Z*!JBx-prJ7$h9c6KcKSI)qriw^|dY(UK z;J2DE`{Oz^0rggh&s?GA2Mpcvd5OiKv5#>}7?@2_<+mR}iH~B>3{HYon3Cb{{zPsX z7o##;#To?q?GIN|S-HAl5d3eqYmZYtV#a3|#SW(phx-;pLn;!$xI1UiOE0ND<<_*f zZve1|b7~tit{#3_*8fX4r^Y4&0l$jlr+iP|0)*cDtqa`A&31?d86H%$>++CiAS1Bx z7HzH7W(=7_+_Rmo%1m~jxvvF0w`d!L828$Tj`V4t&>ngAmo)hd9WFCiRA2d~USlg% zUxX2@v?@RKm#ALC_x6;`E*x`qR-uRe-)5Dh^S*{l@0uaI=FRK2emk~g^@5}Gt_EIj z53dT>jr{h{m3brcoYUvecBh3+0D=L#@~dP2ko`V!I1qTc&A#n@E+J88%N~)!Gskz+^X8^TU{5BENe4CC z+`xuzbfmFaD-)j0pBriv$uNM#Ko#L&;y7R)%-&NlfnJ}?KqKNJA`IOk)Q>HeY5cER zRqWHR={h=0k^Ia6swglABf?&ZwLbvF2jh!0I+KE$pa7DLsj~>Z_x1UhhY)Y0W~>Zh zLxGn`>p2pigcoz8Bz%mKN9btu@R@&3FfA~&XIyH{$qj?I1vYQ*WF0yjjcIIBun0qGo@%rdaIgzdCgkC{;dyG}Yh}<1ES0ci z#oQ;b3*v^q-=BsKU5NQ_JolQ%Z7#;3ndDaFwpE?=Rgm$b-JO64=?dL@V89?UytXap@UUYDkfQGgkUFz8b8lkmkL148+K9Ww`y6r#JM8; zskAoc`Mxn;G)~3R?oubA!^z^YHKQ*=#%ze zxd(c>!{5syJ%W>^1W@RP5Kud>MVnJ`x02|B#m2(6q(2#ZNLbL%2P7plur~o!px?@- z3fG-6<#K(0^gs04+;@f|ddWEX=1yDWX>^E5qj^`$BPGFTQNTibCZvx!V8<2xPO2cn zpaZ704t~`4H2?gZA_X?g$ccN$evx*666*aI{T;t%#f{Abd2_rx4$^6uJ`AA9fWC-8 zHRsh$pugL5_pVFCGql7)oX)zt?rK|0)9$Lj*=Cj5^_9l3%<)4AFc2frE^+$zlnp4= z%=GrW|E+p@*#1@2R9%Hm@RnRBfJIeR@sR^W38b5Y z1?B7=M*45;|LBV3{+SWI%jBX2iG-E0i}++Y2++t!x+{S++I=%moQAd20LdxGxCIOBwB|cd#0l<2J^8Qi<9KDIr z(|#`81Q9N7CilG1f#L~^EiByC(quU4UX0&$vbpjcAYo5JtN*xHb+BGh&(EbIdZLZq z{zIq~M5#+~PXwEmq=CQyqNh3J@(;ow74!uhUR;+snH+`wcT@6Z2|x-@S~#EMs8xo| z6Q1K9t74R;)odnNc23?Qb-r(6)+R8l-9(xdaCg>;*nR619*GYqG;Xo;S;gK5jKq-H zmnrk13Q0nOFA|{4y(q@vW>UQ5Pm3@APXK4_Z&X{UI1Cu}ASw{st<54TkO5nlWtAj2 zT`defC_)2Uva5L7F{gy1>}*&4rCRu^!48y(l|C!V?W+<@exw7DzAIyTBy1B$s7(qc zkTt&@*^kwLcRe#(!G|cAw?ydp+Ks+wI6+N&RFQs=;l*SqIEB=mg7$zB{usE0Wt%@| z(RiBHRGHHx8&`9qgW;?^;-1nXeE~<6WO@CT!D{jrn?r_VQzXoymM!rO zFV7AiRvm}hb`Hy^0s%X)ef70VK${cq_>f0S3bT%tY*cbp{X1b_XV2e-hdCg>bu_}a7ds1zN~U2!J0JzbSa1L|@oOlk3x!%lKdhgWR+In+`h`Np z+}#qC0(p2VJ&~O=ZjS}-Pd74|t#!nET%Yx98!CW)mPVldgk6t_+Bnwq)C5M{o!s=` z<4~j|io&_ym1OHXHVS9pKG8QF$3h~g<+u*%1=gQ_{P>TWUb8XRdtQVj2C_39C z#C&67ss$QC9tZT7d{dVhIhiHS!Zof;%*gg0VE`CY(Dq}pa_8)o)q_Ahrao^V^j|7s z!6#XzMXqMHvXJdnVp)In(|D2VPLhcgnj!3+KgjvFp4-c05R%Drh44R%(SQls_yslN z>4wrU7wp6vIp4+e7bcC;Ywq39#BcjDbHN;ddPj=2g(HQLOrEJ>s#KPI_zI{^;F^uQc86iz(sVg{b1F%smn;;ysp@|ImXEy zYX`2Q#)Tt4^Vu9|;h%;d&VPYd1MfI;I;@4}k|Xpy2U~5!c(`_-Rh}OrbJOLpC0Zv9-fj7 zS)i5YxZVET<8Mp#YGiiYXck(5^LKRLBK0p(8c~>(_7(Qt;};jn`P!b2n|zu~#CUWx zg9_mOtl(z_cA1#q@g2IrU`i@zu7EEDQx@r3b57{rt*vxWidDcq-L`HV74B&Dr>9f; zZhqdS5rqlkpGSpGig~bib7WSOb1QkX9lg6&m5j2p^Y+EkRAhHX`7g5ApQJf7=O8KO zSN?!~o98lJoJvx-AOCgthw;iOfwPIQLBKe!Yv|<=p{NmX@&qt1u)Ek0znMq8j$SQg zhsxe`=}nZ!+LGNRHNgAW;aZ%Z1RrelY8tN4rg@}cgEf1nay~xCOh@T)l~b#ugEh}d zhe?*tj9=jWBB(cBb@>GpT$PkT0i_GvI&QgL42f%hX+!Z{Zf-< zdys;5(nrFT1&VHo+wk7W92fyM&~fkYA&NT_oAqR?CPY^$%dkzhK9aPElVi=y2xb2Eo=yW-WBZ$(tcC13D#jd-N<3toU}b79iMf|0 zL=K??!~WR5gGZcjT0*RL&2Sg{WrMJMG=Lpt>EAHkxsj^lUo z+Bg+?@r#RWn2&c);obPNfVGbAzM-=-`l;FJ_A9X3`I9WhZhp>S`9jLBCwm&5S_Kja z-Mgl3(UxY?q%ayVx&)7$a!f?+eiYr%h%s})%mp~W_OR)FAL_1Bmcvlc64#`_=$DvR zN_Gf1F+075r?NlcRe)6ig(c`HS#!q{np&9d(QI`zTZw|=fMa+;nJXc?us7llO7$~4Odeq+qJK>rla{ijT$wR0DAJ^&s|I(un_;zN+WlCSZW zyShrvI=;gP+VF@z{%;#zz_KP&U3U`YbB1VD?Atuo^}(164Dwdh3b93xM*@dW&^22~ z;WrM!J}*5jcvGAg)(DzKBhARUrNlMu7Qi@}$srw#lh^*xlY-daT}<5`qxv9!o|T$M z#e+Vx84KQ%f%a6LQa?pMljToyhYDVrR_mhlqBgd)h3#yku`i5WdVXtj$=KvRrOY7> z+^Ke)LqeANuRr5TSDK#B&yboAR<+AOkPA#@Q}EM{TzEl5N2MPW5MS<_YnQ2FJqagP zHs~n@0?htVXYxhx%Xi|HD^A(0jJ_IQ5ry-Rk)JDW?}0=q*%@tVT>v4=U-m#V(BzXB z`*%i?gi3*>`mb+#L(tWa)^$r41lo(pA@KA7X0EiJnd2Mhu+X zQ4+v-CxTJngfio^e2vq*;(%ST3PhePf$E5l(G+4|c?E6Z%Hi~*?72Oo?9DP4I39@NNA?uc!j12(S^E&)vy`8{kT zF9CeBzSw`5dM!W;4$FAj-oT9?mzu*BV*V7GVDDX{Z^}YB7=$(qBiL^oInF>B9qK?sR)B0 z{tgSRmOxO$9(d*iQm6X9V09SA?YNIzFiRIPUkHdV$UKlSbV_Qrs45Tuw}R(y>0l>t zJd}}M`Zt)jKCcLU`MX$w&!GD)tf+W% zsr}D$?7PSLpJ%l3AJ$%4oU0G{Se4&ZD1i}mJyug(5uVYwLp)HD>hK}nD|7&>b`2k2 zC5#)F-dd7v;ZVV}z)8_pAjdx2WVjN78whYZDfU3HelweCN8{@T zuJ49rJvFQXZAR)$^~LqDFlF`2DbIg;Hc8gqH+ni;md4uV(?x)LJ-j5A(#kPcSrtxc zT#i1U6#%6g*uW~Z$g7EU7JT%liR}XHl3l8)%!PQPoD$!CW@^5poKFWI6_ zsHjE?V{E#+i{zbO{(%z}X-+g&eunwhcG!JQSRD|F-Wq)G4zJDD;@<*UKrgteQ>A4)i62LhSfApA-Va z@X~+(+IFWN&iK9Q)CdkWak+Rb<3NEE2sEAI@n}1+udIPy4``w|KiPUJWKKBe*X*>; zA3x2$?N^;I7Z7AUi??9GHqso(GukNpdd(m5@d%EUA64kCv?(Cqh?bWLJ5fJ~`9(^N z!qyDwPhyGq88nciEDZYa=4x4M(BPIq0zSQz?U*!D4Ano}<|Ls-jXaO%G0eKgq%$Jt zF$3!{H;Y16KQe%yQ+IWw{Hv&-KuwSfhsqF(+0V@|CJ?lwxK?e;CW+zYA~OOfVas?D zO4br}MTH$}8}tU)#YfZ0H6)WqaD-C-gTP5^vh^taXP6%qp>Di<_yluqFNTkOO$J;Z z9*>|%PF=KYN zH)~p5 ziS}kQYaAnnX3_quI7aZfg&5H0ivc6Cl*-v?+Xc`(ubG!VeR~#g!eL7A4eY)THKW#}=TUsCmnuY6o@(Sfth}hwiIeOGAjaTc);<~)dBm2Y$qzG6>;p6y-PCIlM zHtYyl79cI0j|N6uCZ?R++t%*IFRF4xjbuH&wxjm2z4VV_u%PVLGpm4V1CfxY)@cSf zhS{6|?h1Y)IN%f^_p38S8>OQZL!GCk46Q=m?6hTVQ^=VK0r=rV!Ot)#_SpfrT67RKJYaZT+>4P|0-a3WEmgZ6j3oA_&JM6F_jl8g+RL&~XOK zY^~dOd^xIV>m-(AnR;5x;Y)pb{ZUUh>Mw>fn&%pF5<$t4ki;-n04Toc$blyl`{y?~ z&FS~h_fb(@?`Ke(MJ|V3w`h@K+Lmi}&5%HzjH_I_m~#5^r(|g3*F3u3Zx&hWq!y;R zH)v_gFU`>ncrUb(clz8q5c|9i3esqGU39?J9S)+S-~QLHx(UzF>JZ@Xba=E$<6`LO zl{I&IYIM@UiuTYUefNzCmpNMHW;Ib){<=%8%s~bJF7P_+#`5^2-lt;ARU`GP-t$G9 z*=}NmSaJ|MU&zyO^dm93Z+20Lf&rzuS2^&ejck((3YfG+wX+_UEIM-ptc4-mQYQohP7 zmC_;MKg;5>mSxDDoZ0fYLUe5xhEO#tM>Y$9q=BH8<%~lfN0GR^TI%f|yA3c&CqlOq zki|ou4iv@}l{f2D8tMHU6D%u91}fv2>=r$|OXr5{m8dZOZ}0HA@48ByzD7zLlBNP< z7l5yE$>Qc$m~5} zaK7!kv9{~QFR==b?;xITqSdM(*lP&U#rcE1n9v$Zo!k26J1xvPz&%uuwwS;dQ0&ed zPFB3ILYBiVeqLBJmgjKt>_^i!0^GcWKTxH!^c@&jVt$UKfe5zZy5X#Fm>*dXbDIo> zw;nRt9-W>}0Vk8S=Zg|~KtUU@fxF=U`-KuhtSp~l4iR1(694|)RAFP2yLl>euZX8( zFO5g9^|#ShyTI+PcGR&uT?FErWCFf-l0G&R$J52Z7-zT3D7+KAtdX_YQ9Omx$*G{W z-<#_{Do02+z!9y{q0>T!u-qX=Jsf@`Uo4C#0Z|+*8RQ|Q_L-u%^QOwl$qkA1nJE`X zRG&S8b-J7NMY11v1H3&$I|$=6x0b7M`iI_R&9PD4Af90?^(+je(7eQL@pech?P1&f zJFSO;j2e#-0T4`ZQsN5AP6IZb?acpCx)(Fc2#-MaSh^3Qd5&TIlpRq{&VQ2~kAC)k zR-zF2@MBcoBpp#x)5?7TFbkS@0kAuUz{`5Asl7dskLFyEl$B=~7Vfi~FV01FG{aYs zP#u$Io(ON~b;vO>;LJQR%88Q~`e`8%x!b#_vBh+3u43HFt0%l02ZTx5*5vU0jgzCx zzEGmhY^v~#F`5Q^hEW|hPM&TlPXlg8NSKn*#roN3-&OtOebi^GPGm+WPwi0yyn-PD z`*XSc5meK9CcKA|ZNWG?cKTYaxNjo#HaG~})Z~I7JG_E^GgPhx5npzZRhEq>SPzGy zWjr0hi75pXHE$+%XgK3{>Mz?ewgLUAC{iynLFPE@eVtO^K=)F>h|{S_63hT(c|+<( z^D{Ux&{080So%4i4igQ%jDuO{W6~S&i_DaYlG18ul@w2F1xCq9lDYv$i_;Cj7=CxSziHXXr08r%M_ zccSj4G^b{>?!{1GmT{oz3wXYgbWuDWitap*C4BfeS+0@hv0vZ#$mA&KrE6$H^BS0# z`V-v=7rSP0{G*4Fm}*VT*}iM?;mIcEBcmc!b3Np-#l+uXyOHXmHV8Jlgfdt7t)(=r zUzk0Ro6ry=B0H;bq;LjuHAULic@$@=|RIoD<)am2nTep=G( z^8-YNnh^rh!EE|yJ{a=7o-F3?{#2Go6{uEdI3twW#bob~gZF=)o{uZ9_nfBO8Wv2K z$~d9&0e~`7wl_zcL@TAwKrH_%I-4i2Fh+Z0D~!Rm^@5-XG+>JVKl=OLz<%3zdVvHP zyNvkwAPN8wnw6@k&N_nvsTHq!;r2*;>fA8P?|*!^NTfZaTy$NMuk6$K8E5amvhMUI zg>Dv!HM(0W&FYy)=d5>wV=-pJ@iVTQM09NTPTbDO66=`^bziw#ng6y}653m$?2eW$ z?XvyC7GW8^)3#vH$lapLH01nT?Xtz~0l}1V2UmDIkWO=?bba5(AWV@yAs`41okab| z{{c3J37j66Cu$qVjcy}iSgm=)5C#E!Y3~+ck^O}A>GMMf z!36eUd1yX@sGXF=K3hw??ZqzA{{8>kv3|CC|Fyja!FY23ZAL9sMBucA$ zTNT1d>}dv?Uw%d3oTE(a7%X&mtuVSUu4Suf*R?XN)NS1!T7W`Epz%pDe(;#r1JI^$erY5&Vq zc#X1Tw61LOOL-ii7Gli63JT2VKjZ@pMI39g`zZN2<(g!~cO$1u?(YjSP_UD-x37XP zr=#2JdBX5w-gMn8Eq8cOY2)2#---9q(fX$e#`6hoK&jtSG8@J-AD)wVM;mieB%8IE z!|iv*BUiTsa3MjlNmbZn>S9l-6gazq6oSkTomT5BZ}Uw)k9EdWkC);oAo7{_H=?T( z{X>un6|R0kg50-#$7vSuozZiLA6V~Qkq``sqM*!I6^vKGQ6cwpvc znY;Ft=_KkYAxz<(kp;r3(iaP{=n9>RI~6MRa-pd&Xg&lcadRH z7d7*t$Yk)mm_d9lofagtu<$xWe|9Dp+|yrNU6@*-eV5~?>YpCvd(m$(7QE7IHA4cU z$pM7~BrPDpez1$V*LEs22SG0?XjYOwv|*3TAtN}70HS(qC++Kd3Pks#SR#9sD3zoj zkhK{_U8@?|1ohmaZ0j}XoVFJ+68Yp;xj;TmImT7V;Gj^t9g4NKJ3#vm$FBiCJ2Ao& zw!rK$;?`}&_>yn`6w#^PX2V=`H+GODjHj0+>XBbId;)MsNG@RQsmn0}>cjlQ-3&z~ zOuMo$3J=KE~I1Ftk)9Zv8E_I(ikW!#uiN}NT2{VzmxM72=+*f7Q9)a?pW znwGDfqnDzyT5T1fL<1w4ivy%cm>T?CYF$7MlWVYN_>~oanSdcnyAPq*Ebn*x4#{$o zy0nkM8q~J({Ns{{wRFDx?g=CXSCuZNk=H$Rf%yX{x{ZBKKY9b&owH1O_M9T0-ndjC zIi8+l8Q(l5zy1h`@(A>n{lumNs#Np*-X)(vXC&wYT$e85k%@JCpw(*3(K!4!Ql^|3 zC|)oK^8Cf%wqck(^TSeMmTvMmWW-2!!SkLjcTwVZZs|6&^1Z!~g^Hr^o+40M2l0^y z2>f+(E9#?klSg5zayR-Qhw@)>phpza-_1R&PR%QE_lb?u)ZPML^2^7i!ZHVeOnoQT z%C_Mp4fUqrcy^{u{Cn+nW#Mc1e) zt6?`mrP}Nj9s|RykD{OFzapTC)FqDzeEWD{og1vZFM7nDlRScW>K;dF`@{CgyGI?+ zqarYXzHqMuT)SZu{$vgMM7Lz{>DY)tx9(RrF?qWuyatcFKYxls9RY4}`P1YF8V+CAFBIbe~c3iE3lPNemnOeXd8yRJlm%C*oWJr8Bof%NlB!r za>dnBzyt0U$<5yM$uWmxNVXW@W)P|V-(@uMgVxV*Cc)Hx=IP--epO(bYvjupiPr6W^I~AW?iC_mK(DE-T4bt?|61pe3m45YtL~ z7)%hmJ|iWrIm%C@@WA?m70nc3f-|7JR8CS2YZvOUI{TLf#L1n!={|zHS;tZPYuxal z*DdyXkNkB>X#(ifda-afG(|Xn)*IIEO+ZN;xxn-fJkwAwjXD}$v?7Fx)JR3}BhhX< z;C^G^OL@=tgL5oR?bp_un49|*W8HkscyAGq;80N#&sR?D066~@Az||w8Goc@-3kvZ zOnXBDcOX8uZw=<%W_IpzoU8tpU8ddIh4q8sX07SkOURq^pk~)AAf5AS(Hr^`e!F=lh z1cuimFrat}ge^u&2g(Y&IaTyD`^7g5Hn5u4GKT;S^hU~Q-Cc^TEN})|z={=5+h<{X zA1qpu2Hg0y^+USe4ai6X2-M-N(Svl#+g1H4qs@(qHrt}iN!`Ca|2peG!{uadRiN?K zGk8J7z~sD5%(F+~U=vg~mC#!Tw@zo`mNXU|yhNH)sPI#1>eu~ChffEAtWztE%X>^- zt-0C;G3U=#Ss)=W`*qbMYTos2C|Usfwpz#|e-M}`{faqIDA}B%A$tS386fmTL3aQA zt~!sxJV}^vvC%XOx5atRv=kVuJi%-nI3Q+;N^^yvprRW)M$QYez6*xW3x|)(0$(#T z<9Fa=rE)3M8(;;>)5X9dNSwzOId$$&v}lpoiozmPn$u+FRwe@Pzfyz$6{eCf)Le~z z@pn6rqT68ke#&k&S;*B$jucO(m1Y*D7whs|zace7Uk+~oaqUm*sdPRK@9wXZVXZsG z`IQeJgStZ30=*mxLn5!F>fCQ^+;Evk0C2(d2#(6AHSz@2szQJxd)jm$q(^j{yQa?v z0E~aU_Ikgu_W50g&lkYW3^5b1zZuYuWTXL$;)PVx`7KNkz~}vcY`uebUEdo%7~a@y z)U=J$G`4Nqw%gcF!^XC4HMZHX`=|Kd(G+p%9SAbq32yJl*?iFmeuDy3oNo+s^P_g zflQNFy`rs(6DcZG6`ay2?J(UaUm_`#8PlLbc}#+gzyU+KiH?^h&xH_{ZLN=tJNX*N z>r*=Q!Mgf&k=5^5AdGw%w@SdZrt#zMhB#-n*B=sq5pDbf@yTc{a?1`Y%!xG&$8?`< z(`f2IiM{BJCg6C}d|s++eW?5p@VWcLHB zLwVnlfNP!%2wQb~o!nAnNL&7z31&m!1%Sa~Bmwb5RzBc4y2(z^K4)`IcTgm{}L*L#hf6CRAMUcn^ z-gse1^f++!5`8CiJ%bE{^}a^faS+@7LES&(En$qW11>pG7W$fGM&&AVVV0l&8PvLn zsg}NI{`wufg$goVWzym4{iN;7HRS$5P7n6Xj_XY2c9Sg`q zLwq-_-|b}tIlvV3YIYW<{M>2_^7(HpOFjR(;1~9KUkgaxqsS!Fd4sm0%j^GlDvRI$ z|GIUDO00@~LKdMYUhME}yj(?WhT!J7e0v@b%Ap$oI=dHTP?&}OEdG;++E44M<|_$`^Q zxID!f9){>=iQy;#@|V22+p~uCV+eKy=Mmdu;7zWnlIemFvV))PZim)tz7OAY(aF-v z0uEq5nP(RiT zKQs(5cIBURwAB(Vj4{RYB#!pM>rN@|4GD>bD!}H3LjA3)ce)oGex(sUlj}Mbl?NW8 z3#+|lQnb#wApU(|ZP~Fg;+tje{l2Q*=`T)s4B{>n?L~Wzp_@9>tNyig#(j~nhEHLH z>Q^~=cTL`}2$;r_Bs_3_c{AH>ZiXgH#QJdvWiYpwn6qLrR4qT8JHpjwZ4t}D`)6Bj z_D16MaJ41GO3a%*+Fz;{60NLi?!w*J!ch?i9BJtVd~$k})?+_Ggd^fDi}>HxLo=S^ zf@R=l1D7;%D+MNqy8?GDwYL3bKe;pTy>W=vc|>nx;utAOPai8aUT3?#QIqX2R^_QY z^u6(-Iorqg{W+YPuCFUQhtBA}fVI;lX~G7ZQdc0#rxT=*{2>^d-6|9-3deHx<&`lN z>t=XQ5HZ*ydEkb(pA-%lm~Wnkd3*+0PDs%98e3f#FoKXH{!l(OZu?2gL#6b5t-$DZC(2F&1>v=iWAY?W9Jf=iwEU$%WodZAZWjhK zt?nsfRF3!xspcgm)~(l<6LA9@PDHTa>9zb3LzJiUk8wlmm~fmkvkNfWUIR8FpgLFD z6-@c=Z$g%36_N3^YrS-}+KNwYF=pKOZ`pIN)#c_u<=z7wVnFo90u(_8Ez$LD%ShRG zmcAaHWR6`3jk=z|3Vbg%(nBV>Z@narQAmS2-QVd|{yl!GGP(H0abF+vVMA*C2O0L| zE3JP4TEE4&mytW)xAuk~d~>A`AWhAY_cyKVU}#|xYNMuU(Eue^pH+3Or36Bx%5a({ zQue|cG*1Lr_2LLs6!pKC*o)S0HqQ&$a8f{8;X=vo?@^kZZ_2=`LXm(deT=FwJJSQ5 z5y3=FFMp*VJY)|hX#B)U+VRw+X%8#FQ+(8agJDLb(99wSa~W`Qyz9k&rJkl6$^9N2 zV6&GLA=P6PIy+_`%jD#{Xuu^%Vnz0HKSNngV}bE8t)6&PajP*5K(7XhOgcyO8hy9I8VU*OQL?Bm3eo51vjf(Tc znzWPcpH(p+%15i&JYZF5zoea<@gxBkm5$sWjn3cRDSYKEjC1!*!-^&B$A-QgLfaDT((VtvLslmq`j=+~Y!oH4W5GLuyUI*Ss!Gl$RrJ+wMi-S9y~#3g z@;x19vb&Zj?+3tl8Sa4vsbLXC(Km6JKoMvJ7>u5(YPLG`dq#hj3mLcAk{ru}ms(rV z2#3}WTifd7(gk$QwO*x~rKoxZSsuU~;RYO{v54XGe>=`ZDOL!z&tw_!kx(y=?bzAn z@V-0KIs3+v_q`WIpRM8r;@coOhwLqPGCxlMBHKestV|h>4U^bWhGOPQqXGTIA?0vu z>6lRPrA2JpgnDrW5O>x;%Pbk&+Ch%8I(@u0mpZhVR$;ALEy=Harfsw~r=*napgq3_7w3Q=@XMd9FL9$fvBQRH5(Um&hwK+++Qeljit zdCXHkL08sYJ2`fY+Gv&*W&&=5xlMKJ{2#nM@nN!dbw}HVdS&Ik`% zI*d0f?$=&AT$S@nP8PF3JYkF0>mvAuK4E7p%_K(mh`y#Niq$Lz%@AQyl&oTm=DC)Q zA6T;aUy(P=#}q%UtwR0%q93hL8YPtY__%dS+xrf;xpZ6R)gNW#)ROABr7O(Ovb^B# z@-?9{Tf_gYxHUM{!x#~jskEP3T%N{$(<%VE_6IHC$&7UzbF1TX4;MSCNc*(a&i7?NN}=pJv{di`eC6q^Y})|TS4|WbV%LYy@N?D^>oEgKU4s> zOkSV1yh0!H&qUTL?5bYjdR5FdFEUL`&l%TX&Ke;CyQKLo z!IL@u0~ev@Yjhmw9Lb7BZ+;2me8c&!ctaj z{HoapcC+_JK@i)$KI814B71ko0b^9c@VV{F1VMC@R(Zn2QWd>a&i?je)Xd;lt1`>& zFWT9(1H{Yoiy)QyZ}*z3l`NX;6VZ4GI^_*}(c59(^>!$ssjj`7`pK09=-ua;uAj+p zVpV2||3L}h|1dq+-rP3ldzU9e5iu9z2#y3^zzO-7NQ&dTp5Dgiojr#F#cvEi606~p zUQP&!eH4bk>Ky|+wYBXuZon&-NdY2DIm=ZC?*Qu>PG#l+3Gmz?SPV$M zBt#Hw*Huekz)*-WVgsL7Vk2+pZjB-a3eBBj*%bAY`$GA1&^uo3ax53Zzsc4x>&Jm# z2)MXXuWHld5qSM|zc^W4;OZ;nXKZn3G;t{s0ACy4a;>$gE}2ojBT_5vKF)jAUc5on zPg_%OKjaQxZiWD}P4aNDqaM8oaMAOdmg#@6k0m^xw|D+VX60X@ge#dIHjv`rNGp7a zbuA4Wd19fi#YeDpit5xW&u`ml!P6IfU4EwrCm|J&ASnD=n5~}`7n!_$Geu?>x~OcO-Z!M- zICOHZs-XRGV-e-=AF)#xnoQ!o;%azDT2a;iVnQK$5+an)uEi$1=92DuGM16Ad<_%= zPp^_B$r4?p_>DIV^*hD^5vGI*s<}( zci(g;w0B^2G8zZbgbaw2lCnBiZ9O@?ozrRO`|ihDt^@DcHLc&RAmIb8Dwt6e@!7-_ zfKA59>g}IcrI-3|YU{_s90PktP5W0MT*A=)3e-h{ofvTdX@hq@yl>??A05W(x7j3M zLlaFrD;~aWqPoE0oDc43{JEmTcXn!!pHQY3y0>{$nM$7-QH$oh?e^=$``|g3lf3Kx zqT@G2G`}tt%3G)ePkU(iNJUT4AT>IsPQOjPjCT0LCTM?uMrioXtZ%v-i2?|ahnVMz zDsPl2X5nCtb(1yFZr$F0gq@rw5D8i?T+6*e>%6NjM`1Ak0sWePJYR0UI6g&O3iO?bpP{<|1$DY=FCQ^*?^iGY5Xd&wl8 zwf7w7niI2KkPDqe?vYNKVF?75%?#+a+}$F1e(usMje5aOfgb|8*cS|ff{!j%&uWsK zgs4nf%ou<#U0qi%Y+wg*tQW^edm^%UYGYUJ*o}AQKH111iM2Hh`0x6Xrc$5QHM&Bo zGj1%cx}X)mv^n4j%|sPN>tH$;fC3Un&};#6?BX*MvHY|;v;KU0xSrW2S~~1QcuYz-r5=Q0dxXd z`83-`8}@8aJGIrE=(=WHt+u0$s~eT@DBB<)`*3E`SYHdH_E4_=8*YnJcWpnc#cHa) zJ6FK{at4K2dn+aYs`4|7d!48*gP=IU1ANQUs`tP4TU#m&2(Fo6X{=Xh{5vMT*xq4R z2y_*^854rj?K`J-n=KiPSUh1$#DQHwbC^3mO8K18!(%TPcIbR2=VSF%{-p4D3)gs> z!{{pKLufQOppk0{M(f5P%m>y1m8cs8=Q$?MZP1GIe1^Mwn=;Lcx_q6;9>|BcGqC6K zxu#IYYJ%t8A8#+Vy`$2Br@6S6Q*8$KT;1fv)6F(=8#ZO;^b~pEF&L{wTRsKp^E!eQ z!izbsnVv?S>}p-GIa)S$G>L?t31kwmFbDA%A5k7~dHP(NzlV)dZPf(3vs;3gJqCv( z8W#rs7A@8NX%T^w(5tEsdEset8+iMIrzpm2-H=t92=Pe?;;*p@5&yRc4DfEa!~@D` z{#tiLmBI~eoWI=1Is}h&3rAn?M}A@Pd1f#0Qc{1hIZ_x<#eRkmePer@xlm+qbx~H z&MxATDcqsW1Je7mWVOvgzYc>Sy*Z1rbDFm)*85ep6zavKizi18-2CG3_uI%JbtI_7 zn+HdUc0o2|eYVw|mUM*z{@BEFod|tCl-`L$5Txj&n4&0QH^z)rFExh1H(j4$_3}7b zC2U$L_va!jn4pU&5+1|`iQ)4Q>XE7}c!uua97q)a2k{^x0-4DG6T^dkwT2WGwIAgg zSn{jkX1w03c|K(Awn586pl%q0j{axPf*EC2h_qZc#yY z03xx$WfaU}dSr34eWzQqqkm^Z$s zm`@VhLc4CCvd^&?{~7?o|F^&ZLEV0@((MgHbd{y0>)k)XXR8hto>+bQVE&G%HV#DX z=>j6)@-;9K%EUZ=8hETom`C{yY+M^9E~$@s%VVc$B|GkOx%Z6*^@FU~Sa=Jvbil4G zVDa818s624v&2PfceaCVRFGvVr<-hp1g*TEfpJ^Kw>GO|3<5PuX~7<$IWCcT&ZrRe z;sjkh>xHs^Dm}zNb@)-wcGbPnt{$U;E*SXR%I2_o|ZKeYC z({&006NGg2kI?#Bzqbi`>DTdPkD^e4+Mb9-Ro@Z=H$ z0f6Td+vJg8*DbbeF9Jx{eUZB-v%97US6d{3U2`c{_~sglUO~U2M3vE>&C5!rPl+Dt z58LVeR8lxz`2h|TkDyvA@Ay{|aW-K#IXCTjEBB=Jb~!Fu3=yo5zd0i0eH z?BSo#0+hn;HdVU@9dHvK+JMi8{mDH)On*oMjzB{0fPjd*UjV* zg4?%ky)-?YTLnS$OPj9hO=b7@vI>4t+Y=goig1_?L5gI(=<=;^-CKbgpHVZof|R)M`l@+u1jM#y-t{k=wE z)L#qIyTyEM_jJ`FnPz6U3r{w)LO`urgciEHadvH-$mw_q+BYo5tKbZUx;*fr5~cy? zyNNr0>E40cmt7OW&qADSl67@+r>VYK(Plx^-cv+?w_(78hixHF)~lKX3(czbML_ zLOi;J!Uzhv18rtHpq3)Ksnik5ORDqec__!lqY*+jE1f|^J_Vr7!oM**gdi(;%9`-e z$sn?&#AfSlj1O}L`TE!GIO43gjRpi_F&7Q&$)z<8Hr!ta($P*f%?J+67i#tS)Y_(& zQa<0EYU_5bL9P-CyU`xE*KeV2bDFE|dGpX5>YBFa3=BtIO~|Tof5~~L_@X1Au=1CX zw$&(zUIkCi3heTMUHc1Br14Ln3qh`cj@d}T+x5+xO>h`#_go`%(DvNto?IuTK40?Z zM9-sB6P>Huh|Jtfdae97Ml3g%*8=G*T9FE~jz1o^v-_P6x8?rZt2Ul(J$YgHWJJhU{dIJ1tmEbYju2m7HAB80!Z za&LB6=$al|tTz5!w~1IhQOo*7B2}o*g%kxsCtFp|T9h>T9+d4D@D0nIu7w&KC@eNQ zZMMp1;4vyoYqAI>ftGN~OR}s|kTs{?8q1qedGv^LZyi$zd```H(I$WSXpxqeAbNeV zX4yyxM%=ECp6cn@shR85!438idd>Ots#HcVpXx)9m4PJzo61WbuxsOTBJQLY*mCX<+a&HQ@JeeqKG$c*#r+kPxw8YcU)mLhTQDHFXl zv~`iPk95Vw^KSZWU?AVsw{s5 zL$^R>#A_@m0xRc`1iW-XpF!3QC@UF``nt|vKWHXNK?GH(5Bq)BZsm^XDz&Wu2m3Nb zuT)0;u3R>Sf<3BlYr5`y+%`T*NlijeI|4s`8F@UU$CAzEvCf7-jp^)3=e2T2DB{LX8y3M8ka ze!uf0fh5+~HO=X+Vb(fJY*DMeLDdn1@)rJ7&5-y#-d#GLI4{Jl;yqUzxiR8}VHqex=5`-o{OXDbO!3|f=bcTxqP^wC5 zvH#$Is!;7gV@;GuGFbjb3+h_pU6o`g{nU?)7o{ZcnbQGQCu`P1j+j?uM_5e!n-(^W0q;ksyk?01NcukyJAU2^H7c zp$o-U7}gHnX#?G>JG|vP>?qB*#TVQ)dbGL1y(eH#G0j~f1Z{^F)I<3yeG$hi!5#hPPYusosL9a{JM40? z8)ad@XEfx~3TCl1C{)%Si+TUcHe(-wn6B{s=aj~0$Yxl?hNr>v?BYK_D^}m_SNox| zY)B&Jv`s(XvWoi3k?F;UQu$Zu(xe zU5U};BrLm1){#!D8aCTz9?Kd!n`6nFRFjc?^i?NqYrJ**BIc8TdEVJMy}%q%^vCol zMwu|iOs`gutGm*ug!@CFMd*D@T_c#lK4?JlIiMI-m@dr@T{l0EBr>keb0Ev zhWey@v_W&hiC&B$lXJrfAblyVDC<1Ab;#X1eyB`nFS#A0IoI6ZL#)oxE^}yB8Pll0 zB}k?(k0UO6zF0(_bn7W}6rL^Jg_g-oD?7KljLx6`V0^NtA-a~HA5X&8(M9~4VfthH>B8OhBa_V7+c0Np-s>a@Z zLGq*+k+02xo_ErN_H4g~&@0Q-X?mS(%y= zqeekg*wgexOwaCN9N6|o6-YKho*&^_MKY~{mYpCW@AzXMi6gHvkqb}+975iRTA!i{Umz|0xfXE z{TD$O*kzINs1I28TgiJ0O46;P*fW6GEFbADfd-d9$g$}Al|59?AqNz7x)6oPYfQ5m z8&t5Wm||tUath_3T5)8D)n}qE6t#+sTIeVlH*A?BilEJ=pVAQD$JfV- z9zdr?E)tTth{u!zAWAwBrK~RJqcqwsCa&K1yF1=2xDfNTUBy zi8Ba@SvqvMGw$_=z*HaDp_>+A@UKkW%dFdbER?lfr@v2%aJNc)w%#(v{!&qF5TgiL;15ON@lN%NbX^rPF*~$`ciQ+=@|A(CE4#)cT)UD_^^~1;hig*Cn=(EdRXeY9o!`o}5{zfi(5{ z!k^r689snduas68XX$E>ZeWXic;DPExlq;dq`|P{s z3RS-1&6n5wdpZOc#iA*lA8_h$WhH6hgbB_uCfRHiMxrAEaz^Cf>30rspcr>`%z(Y+ z`*-nHT}F1TN42ZIG`tYcM0$#*&Q(R) zL!v4Pi+?=0Rkz!(&&hnwuUdsEaN&~m*GS1+Z0|MK$Je#@M;tFbug^R-J;zm+c{!^% zQny>}@bVPP@~k6YX96+kpq)o9>m`iul)eM=Zsp1)3q?fcr87>be-23i76a?aDcHrj zR`HMO7f5e`Uie~vSE<1Qx^u{|7cZ)7$Tv8b-T)ac@vpcts7E0(K&35&y`^e7!#;lH z`hK{+{*cLjx--Rq_ma^K&7Amaz^=;5S7*D6)oQBIr;6xE91h(2*;$D%N{W8UPGI1M zYH4+I0C?;A=(i&k`o|alsqWFZbO}Ez%<=vLP~p@j*Yv0@ei2BJ4(#F>v$(ObsdQT` zBRnleZnE|}x+qy3#vzoA%Ht4HL>YyuP?{`VE_)fr)%)HI90W4@RdXX~>{-yJABsC0 zE-up=v zknVo}m8Jzr;5KVruB3BY7^fA#Hl5lRP&xElT;;I4HF=ap!hQCGY_OTF53m<<+hXSL z{UFW(-rO0$)0vq>?~6IDdO&RdKxSs%D*M}lq{+g)ea9-#iG};OWWeWxhE(F%f&%mx z+@6`VSIH3EGFHa!+y@Ub(0s&u|xRQ@Z8_sT*gn)Q<;0rr8Ya zV-r)6`Ip&pm#|36A*uQs4$#^d3xPWjycMG1w}|QAM@C{L!%cd7>bS*5F0oivx*CxlMj1c^q1&o50;- zFWi2sNr(&v=rl{#9J;60@t}Y5Pg>w>qU>m3-=RzCv2F6%6IPKy*fG2}ZruBH<(B4fp?*4owi0EJ6Z80tP_^Cp|9Xc2&S%PL} zle?_AWh1m35RHQu+h8}|ZSzhZ-&wrZ_Kh1*Z}kJ*~njUk^uQ~SI?a=y=7gWNmrTj8C0a@&^G4AYQXn@01f z(z0Ccbg##rT16}9HiQY-Nzc|KA$UW{*dKP@d1 zPsEQtnZ)2_U?gi3EYCotlp;6Xh@f-Q=;?!wE^^Yy&q5D}Lu?oxvMnf1dqFgZ)j2rCGtKR zWu0B`elk#<&2>LiIZIW`pvL?-9NQ)E5Oa<%BDV212A{tf-}6I?e$eR-wReQk)Fxb) zeSv$euy~ZkNz`CAd*oG|LyjWerlAi!XA1+3e|Kl0vL}PPGx=0%ufq z2L_950g9?0=QWDA!24~830yU)p?O^<~xM_P}~L zJR{{_dr8j#rC%3E__E}CsS0eB!XyQ}QZZK zPC6cDeNI2)`T=~FalO(yjUc!R{*qQb1yf=QY)Gz|FbuheLMz-wiZn3`Qde*$D!1ae zda%jVefE(kx1q#BQLjZFd7j^NzFkYBSE-vJb~FmR%lv$DGI3PTV$QP6Y|yh-&Z5=3 zr;zH@$~T@3YCHJn(adq6#ErY^Hm85@f^-C`CBA5|nCWEzQNl+YT1^DaLVmlLeF_cz z7uwI?;lL3Js*>e#n@ba0gXDo@>RF?#xe3fMf*n8<(C_8Cz@q(AURQW1d7L}zkd=HY zOsOp>q0!T26F$T&*4IrUV!Eo0eE$b9RhRMH>{a|PiJ8-jHKBn3tguz@fkT`Ad*Ns1 z^6nw68;Rg{HQz_G(V=Y^c}IB_&WR1O9LQw38JVyne1cw;@+VO_FuC7aRh%62|MOdk z)LPP+zgr@L>tNDk{{+F#N3UwOA8o`@n7kPH{?c&pCRu=H7xO}933vjRS%|yoM9~6|2}fm)G-|iN63E` zQ6#Wre2y`jxH3#%1hn=ZsNx>8@iccD>rx>A3ls^*VLl6Q!B+Nn!Q`mm&2!V&DkriK zkn$jspDaM;3sH)cg!4GN!iZMH6$tNBL_zRq&$5dgd9?poyyIQ-8#a_-zK$=L_?L|n z4A^WWc<8#_b9z2D=vo*$WU$W9ZsfMuoPExYsk^l-#a7zVh>8@!!0X=?34%{=I(9lv zznt%2soS%;FyfqrCw4#Br9;yDcK%%h@xkzJ%8>eiQIdnRWkcFzX!GmHQ#Lu1U7l!I zaH69^A%!Prt0hJ67&YO6q^$V8o93oWf5SfpW2Pn|?^X#hNi$+OOaOHPVR-68G%Xpo zp$2_JQ9(~Z&EeVy93#(yiidkqbZ# z>Qdo+B)p6l=FaAt8u~avccDSzo?Uw4o--T3ZO&~4*X;Xx4TrT(Z8V95#F-5vDL1d4 z_iD?X-L`~tBG!YxIg|w=Wb)e`gX`~<<(Hp5hY$@3idsDk!TG8`sN!u?vls~qEv6xP zsc{LzXMui?#CTp}ue)hL5mF0qLW|U6Glm^h!hp8W)zt$7e`F^wObJ3ojfPVtC5h!H z1c5k2*Bz5r-_&YN2(*9RiJ@cQTHVI1!>ImU#(BUZ3$`DZ7aaBz*_=IUEF_F$Ta9%vjMW76uR$dD zoxkkhkt(8_r)-hQCpp=~gJ^-AIH8iVmIa^AIeT(HH8MySvsM`>%%?E^Pvkx#{)kli zf-r-j8l5=Prf{REGKRQTNW_i!k>d@zYAT1M!Zq17H|_!9Eoe;BmM!MkLruE(e-+>+xl{cmtEsN{5Nsp{6?P`o|NU{I@w-*Q6d|3HJm z%t`lTU~3KMqrE_WqQ+vxeh$2sf6i1xH+_C-q6pVxno^!Pt+Kfy*5 z2_|Ydn_d1VbI<%Ib3=v$GWUL~mWjiF#TJG%Bce7r)9hE!f_*#9?1ufi%rO=hPutlC zJ2$551x^j?Dqj7y4oTe%o_bWvD-maJfgX|UwsIp9)A;8kN-i{69BbRDghz0$<%uj> z#+Fht^L{Y$?{ff<;YOR(K4-W|)?0f^8hx0Y%Y^D0`laS1EIq0hY;5-L>VwT=y6v=7 z8j)C5%y;c;){rV=Y|EUVKNG?oryoQuR;^WI@|IW9;ldNOYq&L{UMBLVY*`TJd5Soji~gU;$Mq9VYDEw(jR`jhiJN6;6vMFChAtwdaohO_9+KqzbcBr?_K*^pjX_0+_ zAyV)Fw;Q5#7%(ys8&NE3S9tzb6@0RhfFJiHx_L+ASiY!V8}2S!-C8!3;LDHV7L;x_O;_4 za6yn>SJT`5^}MJ!NMyNRTh8M2%LNXtX6K}A&aO`%Zq`-kUSd2+(61)&2783F{!2UqEd(R8z#S`hXX>C@#PKTKGw#tjk#$8R7Lyt;D|c2(99YJfk0K*-=w z5}3J5jZ=(lqhhK45%SR*8&<(e8*t9U$JYPD?wG(1^VsHA=rvo%Un?Aj>al-RUiu<5 zDGl_CNT#Z{$g0QR+lcXiy#nByQp2QRwS=W&V%&`0ZO9H&4edC zTE4Deeo!JRHGUs;t9N1$O1x2slGme`TD$=}rHCjr$PIYhsS4bT&Pt%T~O) z;5|&s!EK}8eL92R-T)u~SxAkc;=W#)^z9eq4^Kn?jZtqb)V!A&?jLCW((JUnttv^i z1T3{qyJr1G9B!nz`ekj``ga2js=Ipg-}TAAkECrP#l{X`to$pSJyA14=Xjr(_kd9Ii3JoJ6^$9d=HaI^7N zs-_)1B`Q^C=f~0wt&2aHA@ejl?`$zbaD6~mRdzXob{vMW!hg>8kvALUQeO)()! z%7xwsFW?BXuhdOQF(r-Xwn7Gk5DW)=yC8t&1ZrggxrThJk zdqMa5VyQ)f4xqJ|3tqgMsJh!-uc)w)ARMn&aS0-ON{iTo4JjyF<_^d)Y87}d5&l`m zu%8K*X;+Zy0|`K7m85N`oOqkOQ~Dn}>77u$4ht+w6N*g?J7a_5KKA$hxs~)pMgzPd zYXlL2^_QUjcbp5}qS%~4l>;~m9#u}xmLUx+qckPoGK%eC+=(xl&~A1`UB6ZrC4f~S z=#L(D3`Sazcwk3P`-%>j^S29!9x=WndtTO zZW8p+r=aKUaUdf;oB%)kw;id&I20gg%wW%ST+ci@FkdQtwrX^LtK*{MPAZKKkxX+j`1@+iTxUO&s%Pv z9=oG0^A2ZmY;`g1$Ab#Rlp!r6ri^D9q$`@!Rm!EK+S}C$*OLbORvgZ2Rt1 zij)}@k4KHnBpOoLppz?Eu|bp4mQ6!Y6KV;5te`9C>oJ zr|7*qVy){6WrsI{q!8Yq` z1Uic>BV9yZZGv`b+gtcsnQk_#yk+Y4SHpUy{cof->5k+LrogIW!eFW6x`t%aIiHiO zm+RVB1N@p^B1gy?sO>Dy6967$(@EG>9!fW$X?_TO_AP(xZBT2W$jQu@Z*tem4K~ZY z9R$4e@w)7^%%#esbn}yNnV${W+W(~eHjv<@JhLU2+L6Fo&BxFhRc)jeahccPw%-t? zBbe{&MFiaRDuD7zLC3)7J4MNw_~5v})G|(d@lw!aYA5Co;XK`1S=v(5wC-fViho2Q zqZD={V3nxc!bz=*-Ovq;iN|<_p6xICBQ)w#lVN^05y+k!hJqmi%wtg-(CP1Dy4&fA z_=KoTyV70X$tg(iOj;;N`1i}WUEq#!CZ*h+v;y^K&oKU{CtDbMj|F-5b@e9R*#E=Q zC&^yw)UjSAKP+pZ;Aw47fYtk^X6h?wX;~?%XwIp%- zpG%|G8Kxu5QNui`pDsI*!MWG zXND3hp6*{O;2w~af2iDHkB~)ft$0_t%%y4KJqfAQhd9PZWEmVM1DE{OIFlhpq=}K8 z2(XnMHhRMTY-I_W`SV}k{%ACO3Z}Ekii=dg1f&~33P-6(krBgOQ={G8OGGlfITS2p}WsA-@uIRp{R`c{!jPYlJ7QHm)_~hwzqeC zrM)hcYYv9;diqOHveD2ivPW-^fXh3PnSk= z6!%i!8!t$4#}ZZd1mdzU!1#tT#B^ZrAlFIxE70=`_2S5q5V$Rc^B_H!`3Rn4-7TWU zqX_`ES}Y;Ukk_K1tx4JV-L3Rxm9&7Ml-;ziZuMB}5=^gDe8Uzq_d=wXG4>jJ&gIPL zn?PGv8vU)I1U3C*{=jbCp1BCRUcS5Y8N?MFy+;bE5~MZ$G;Nf*X*m6>4ON}9~r zKv8xa0LSsT;e+~IA`=B5Cmz*SR}MWM4Wpf{Y&L64_&NmhzjYw|-~*_b@C`m%^^!F@ ztyP+2Wsyl4Lzs+S*Fy7*Q4&C3zkf844R%(n$Ve!^Ww@9I3QDRl?FvBR$b8K7G4$9+ zR}R=muyb#*(al8KuN;uLL>?$rTnV?&aNL!suQ?_czq+M(a1#c_wytL}IRj|r!TMau zqtDiIVP-Mt$J5@d<>73p>65#I%%vz&kA~8TLTaqeHwMz^{tlc+`a`JnMwcshcjUGMg zfcn6g7sP=@_pB_;YNqXJW@u7Sw6>Q_qvXiNlDSq}7+JL%t?MVIBWJ;i=|xT)3Q)&=4zrJ>GXI^@WaCe-WN^tgi-K8)o)z z+GK9L#xes4ZKUaQD)I#H-rDK5M*0D~zR3zov}h;54Q*C>n8LbENi{^g~ zlI`GH^(6*c>*wN1lA(jNB~xS5KA^MiKc>f%T#`E+oKUFP65PeostCO!gw4Svr%SVu z(9QotL0T;FSrBq%V8Y&>{*xLhN;{!Kdan_BsQzbKzkbI6F|XE+AMb@O<+Be0vO)Kn z)fxc1St|US71j>kzkWmm;r-!L#gied3{XK$E>M!0#4KfwFu>Xk2pVziqTU)S(tJ+s z*I-zFJPEm7VLibgoOP{f*Wcl?)Ihc%X0 zhQS_yq7*umk_~tt+*P4!Eif?$r{|g}+XcRzXZi^f0IiS-`mV@APayU(d1AsF=}TN9 z^-1Q~cHuT%4?-tpt^3YZ4HOpok! zfffsU1%=z3` z?5#ioye12ZwXBX(3G&UxAj~ZWK*jS#=8rr$jbfw0sGk0Ej{1-BrVKV655OtHpjiWh zv21NnW>G3#R&>89wAjXfIvw3focz-*0CgU-K)w_OXrQ|tbU;{_8sRF_%_+-!kw|GF z!D##t_seG2AmL}&lx=~TCtI2KLH(%$bWk+DxikYS3L*@##mZV>Ht}Nd-;_Q()USYP z%Ld6Y0U~0jXTqypqIs_CxXNjSx-D7qSU%0W30BRC6j9NqgAFE5)IDngxi=tsG#bIu zGxJ_$fsbYmT(uO+$?tAc?N)F|XbF)(!es%e6C7!PXV@{NDOO?a-N-^EfVfzh zIFsR`3O`E2rn>K2*?Rddj+ykX)C`T!M#@2>8yC}jwbW(cMf~9>?|Qvg>NAX0h1{vf zU#&L86#@Zt=Un>3+Vj{!`Ib=x#8y|xVAnG+fZni|g_*L|g*8CjOVrF6q5(w0Di`zW zh1flc&gQ8+JrxHC=$B`-q_KgNf5WizbtTb}r}RQ~JGK2FU*8`QRsnjxXwY+Z6aC{GnRUCTeZLc%hR9$m<$byM2ybVM!4*0ky;pL3(DKVa#*x1t>cVJIGG9SmbPQ^yxXd)6mKBNl#^4vSHm4|PRmRjBX^(rQ zx`%t;QnH6c)`Gv$C?raOK=S?VuJbOC86x~tW{mS=V|Ej>nh4ahxvUGU0Ua{bdsN(4 z{`m@cMQ*FsW|>yI72yXM>N3(Pe}Ozo0f&fN9t5a^Udvbe4ENBpz#Ke%61{-8=lirC zsj9VxBMNABe=AQT9s81B>BBWS30d(b2~AwWe1gBxH{8EexAOCn|3efvVt;C;w$NSs zc`XG}9&a0QV08{j0{a(YVi%|$>}p?1Ba@a^$)0K1iCuV@ek`LGDjoFCbJ2OPx=pTq zB|PA8#gfFRyoyq~rW)2RNyh$hap*RwiCZVQN)2u(2=GWNb>+!Zsd&Eu->;{B5118} zOF5V#jB~aAw9SNt8=)6G>o(V3W)uIG7Fl~J7r!bj(S}npl5z}HwxQ0)r=u~Z{bg?x zoAS($Yl>)ovzds55KENznGiKCt5EQA8{0knh2i=P?A9_erbJqf4}%a`6gZT*vu`sk z2E}IOvSfg{!KWWvuK9bZ9G2_cXn%!-4<&gMBOiwd0wBiWUEj^})Kl)8l;TRrudk|* z*OP0==To$qqDShioTlfn($aG#D87yp9SsbUt;PHS8d}Zv{p#O?R6yVU5+O3sI|ecI z#f@u=^%_6mM!`qgnJD#*`wgq==8E@QGXU+^=YOY3zCWn)R%XD3`t1T9j2BrE25#T= zNKfTc$>qjXwb;-b@-d#>?q4-ZY$f(MrPh+>edIz99pdrfZH9~}>aWb*%x8#$KVWI# z|AbZi4X?0)J{}2osFPTsPfUvpKQYHUk^$6|Y_?oDbz9=DZd=d1Y)23L&#MUx%jnrn zN6?2ydLaH>KYQyp$<_D^Yo4NjMH64=GUezeBX^&puuVaXWAXXOQIto~XIKJ#Y^#2W`4DryPw=1Z z1{*BmcC6T(5X^h)3j~m|_Zo}-)p7;>F65_RQ6x(O+SYk-MlvHRxE8!oL+jS zq#H{2A5(+ubQy*r(Bc-L?kWckH1uV+Ay4BT{0WbE@P|d5Pe;#mj-%t{%Ysbm?NK=! zpn5C1(0)tx?pyRJ8|5q+Js3M+U^R4+w?&ZVG{aNE>-T=N`vDGwMTUoJqE2z}dBC2& zWU-RO1BO7}pl8WsJmyGvYl1+zZJ7*jJ!J%hg_i%)7gaku_q2gHpg2!mnJeNoJ3(J> zR(j#+X!Pa0P-C@&jl5d%cZ!nDX;&MgTDu?cD@U|z??nw^c@#k6cwyR4D(GiG?y(C< z??a3PXQ2oN7kz+g{jiXVYVTy-nR0i3Hg91W`7iL&QiFnKT?bu&fD=byaT}c1AL_js ztD&1(=bKdluzv6gzA*0dKgNsy_qo>#7cp50b`z z&?SS+HIY@E?06V;vqW9Is6C#K7-dDTCqrLflYM zZXKC&1jCX1_U%TU=^q7V84Yt3uc_&*x`EaGfP6CHZ&v!2oZt%cYn|^_RD$^^6a6%| zY6cVYBtwDOH`q(#-_{pmQ$)!jGNM{9-7i!eJ|ztTG#u)#Uxi-R>|Rd}WV0^V zKR4~2ASXEFd!$Vb+oDn9&=yRrr`JWtKCylUx(qT6Y6^?*M;%yRN2 zc<7T5a#d2Hey$KSNdtd0y8Pwj0>mtTAFeIZM#92}yXG9{>!W0^j)6=8Lc)K#? z6moTW4&mJ}hgMYX#Cm1UE<1bwaxJkn-de&ZOW3{zT)2p2dQl9i)n9apl5Er>G^-F7-5q=#HGK!G0(Ub6nx#BvE!P~D# z#6KR}tpm}(&E^x%(SN?)%e=S>r?&P}26Y)3WbE4|ep$!9V_d6I-(B%2c0PPBm>3Om zQwqDy8X9aI?^PLJlM%nbawB(0N-hbcLxXQ=bh^b3T4K7zn1N340vYzN3PcoCAi&0+ z^WGyyWlbrX7^EZp#Xn}xmdWf6zDKi7&$G3kL_>>>%P3^TVRNC8zx=2GYq!}3F6HkC zFT7t?@sZ3sLrT_^7`3Ytb=sTWXX3v<;;|0BLxmB8U7_Q+z>B#>ScyW1Pk9?+r0k89C?WW$(Tq&PJGJ|Nr^)-8_W zk*Vx>>K?r6Qq4Y+N1wc$c@` zw`e}iVgMtqo$5N@UoZo{YmCVYw8rJ(AEK-EDtDTprAu(SR+zlE&hb%dqr`TqF_f$W zU%EO`tG>mNUEWFilNaw+W5Mpm$x9=xwl-Igq4+iDNBv)O+hh(uPdmRldZm z+cJ~rGP+7aE0RGjz1$bLP$7~0CN{?gjj0&-xdsKefAI}GA&Jy8Cdj(Z&@15JWQ?lS zCeb2&#r_iqIXraV(&$aDaA5DXC6;A>9{6glV`oGs_Z^x2cCXQ9x>4BpaN!J^{rp^l z*1mFaevY;1dv-g^csnc5nxLDn8GD~V)1S4*4{SOfISe!TWMN4?zZe7yBL)nB-9hL3 zTX2VWZG8L?Ig*2c1ZbQ}<^vt*kaTdJpg=J!ji;|-$2;IQuv54Gxv!Uwb!Ev!Yko3DXW%(yT^XDwt8+ENPOEEPr9zCUumvSo2pX(=80f`13;lL+HpD% zUabYQ!g?@Ec>DW#B4;PlR)ENqOromVW;oL5%j1_UzWzU;a}na#!^y0n5=&&iJOtpz zMdHM0omJ*O%`a;gZ95Dc9s-g>O!&50#DaZ}Sq25Aa8YWQikGv<(MtQUURH9YKQkCr zkT6h$$E|SE7_puPz1Ic6D1Y1XG5}#R!l;KAX`%Y*v0;>?d6N&u>~G{-Zah8m*bOV( ziPBmn$r^li)Ly*5SFmps5rARam^}{H#A76brI%fo+E#=u%8e#pNo$|K>uE4j*%i3y zn;sCpeP?$6O>$+_wv5?SHc;A;@T_#&=MXf)O~yf12VD!Hl>**W&g05=i=^Cy4?xs( zpG%k8FTkrV1(|;@S=;Ux0!cL66~9*0L?b=hdLOvAjW-i5nyX9i=#__^plG0uQQJcI z$lTZ;SaS8ejMZy&cZh~i4-fg}{s<;+wDg*NN;$unZ=N8PMY+Ch3?L`0&U_hw+R}x> z-6LwSAB{wx1SvR{LU6NB$*Z+}P0c*}Q_L%DpP}{fle|Ou4!=P>9nt_|2TB6C%RZi! zi+C>v18vn}To^lTnf)d6!Gb}p_~n~=`7-}|8B~Xs5Y7RTWt7eNR}zGYex*dG;!9Pw z;jH~57bm*toa8~R#M?`{ds@o`sAEyE88?ZwqrP^h*@oBM0>fa_ z^DF3svTK4q=;QTo9G7z|h0{6{4OhWX|BLf$0jY`!u#^WT28*eJ;<6OJ75iFxo0Fk3yUS`@n?v4!Y5qcVse=TbIpdLh<(;GlQsuaHet6NDJtu` zqFT41MpM)wp3t4<-8in&k(nIgK<{hKiKYr~^grdQqg&UUb!%JLxBjAvapIjdQagsk z^S}L(z;H9mxdG0>%h2OptA=@O?p_M72K~2T zKB!@gcbGe{7MoE0%0=tOvO3OkOV<*=u2uuv#?I`eNeus@PHo$Xy*=y?E5`<`r7wd! zkdfz_>_W(0{)fJ)x^n9-eRhu@_@lHaF8L04B(Al*q^V*rpP+QK*@2WN70tJmlS?&I zu1W`x=&z)=W4il;c{QDv4Yh72>yV21a?Roo46889vi7mx>9F?pAhs{!LPxv=c_WT6 zeY9vqLSbL4-*RiG6rf9X=Ii8gm-{>=Ze&5f@C58&&g5_Ff>au43<%>oQx;?P>U%rK z?K=|A81yKep`B#rP%Nlf+Rdfi*mlebj)8#O&Q_&b5kU%Ufa|2*o1l*RmrRH0%pZF# zZgi-M(ZPTO(ys>Yn9ty=ax*Xhe4x-{**XU9uZk**Hc8iGR;=bfAEDw=TSdDz zX6)5*Wc5^&nK(_ctl*A*Y1epnHlPy%FQIo4n{KGh*y*L$L^ie zPMYV1Gt6T5^HBTZuPCQ60{>oK0zI@EO6oZE<|n5#l5Xdm{g+*GA*Nq$Hwlj8&Hvp^ z_JvcGz%BAU4(N1$O`&MS+=(wyoTufWh(VuSX#$)Nxh&UeYV((<`t+x4|7{34Q9OBc zX?z!?R+Aw0)fqjU$=NXU#p`5bYQ!@kQdW_Y1UuuT%t|!OSsI#51!Kp;Af}QZz=0Y~ zMwfJ-5=}w{*nE{!&}uQVih(O7j*!&L6cjY5UBh)BI<~u|uqtBR^tZ6~8m{j^1o|dp z#x=+Dqa^eHmSr?pzyfY;OC$nb22fIMj4Uirsw-Kc>vw6}tb|p6h;K7dtoK|VXRdKG zvx(XEG{hGAkYifge=E!z&y$FSwjlSo4Yr*H8{N|4x(ODmvGY zZS168dL$gO*hsD&U{t*@g63&2b_5cmQL)3JU+Z=pUh6&!IU?*rkIdrdpkErt_ZWyl zY`M)H+b8kctLK>)3_>}ye&v5c=Lc_Iv$D5nTIjXc|H@C)?v;5&sdjZ;$&Q6sNRggr z&UX%tC70K6wt$BKSeRL4k_fJ9Hm99bbV-Ck7D|Di<&RfOEOh`%jqi#Fj-#D2GG>=w z2SAJ6wcW)a{$rx|_b7nslf?Y?*bl8^GIsID(z*q%a>t+`sk3VL0VfyU4l;`a%ukqC zx&nS%s8=S-MadeNJqK7n314V~*?ax+{_A$$%OZ)?ofzh>WLdiZczbVJ8vnYqaiGJI z+PZ4zvRtVWPJ8ll*L|tu*EA1l@gOtvovk6vY^znS;hc@Ks=t_1j}B|6%iL8^s3(xqI}y(Ov{^7Z!l83Z%FRRV%M>sB(>5=$1L6(^)U$AdyPnfZ0ad zkKR?H*VV6a){*ca0&%5j{Hm{_E=hnY5FFT_1NHgK0ha2=nsv#CrDSJqw(2CUjpJjEH64@yUivJj2ElE1V6iJSC zuv{D8=cFjh8skxL8{*G`UGAOk>TO~-&p#mm#%!i?NoXDnoaq}ozLtKE zS|1K^9>QJFU_qmAs2%aQlKw9K4QQT(IqZGbiU8&J%u$gG0*U%KsqfN%x*y^6-lazz zt;SkJ>~;z~MD9@7Uls7t1lu3n;Cq~9<}MM9smTkR{1QwzHdA@z`T4*qV$A>w@Zp3G z9afrDboYb0=o2$_hZ_)p2WTVD<8LQ+hQ<+rOWFTema?P6y@otSTLj0{y^eStCq=Zq zKd3Vk(mWH>Qh%*_>X|nQF6xy220c)VTJK?*g#q8$tSos5HLnWD>eN1*vrL9pz1+*$ zdB!PO1>@7Cm$dSAiWu>^XUW2wSmP|Zuv8@U<&)mN`ty5d+}7D)?ZAq=<~ls|?=71S zl$&$&W2}FquHn!2(JX}Y_}szLTW(Sbf{7uf()l? z4)=j@-9OCCoLpWc#pP^z_S{pmiBBCtoBzQxu-dt}1lU=kw} zbl!CnagmJo1*07jrg}8xTr~-Qzk#M1Zyv>dQdazpSl7;M*0@5mlU-P>e)I@%W)a?X z`U)qBfJcF)H{;xWKjY6;HS_juL3FEs2B+?dOC~`4gj<3xtah0s32+H&XDFrV#sj{O znqr1ew7;O3gTi{EzpQI=H)G$fvnRG$!y{I9Wr*J&^=J_MX1D5&@&U9#rY_t{f&8ms zrei7zrMbW_Zr)?S?CKmL2x^R)CB>!X1i){TyksUJxOw0O1K#2NY++Rqr?mS5AX4@t zd>O^VL8l!-#HZlX^}{~`C5iNzdsvXaaRT*!2;gEfxVJ*g&NYt2F;1h*1~cI{*^D$% z;YP1qjM+0EuJn=ncDU=?$>Ez;Lo3Y8D;D{cLwiwN=m(7fOHMcs@sAP26ujUN_;lhh z@Ybn-#Ri;Cg~mH((>cb{9D()Nl3S-Q?qhNfG=GjGkQObKwY%T}FK{=YaYhtMhp~I@ zlP`@tQ;Svp>Y=b&^vIz6i)I`96EL+@Vx~Ou0NG!R$N$+j|6t>Jy!NWt#s6C)k@HH& z!oB=v7+$zy)1HeQ(RWh?E5OGn?VQQ+v+v4-&_OKLeiar*U4 zx)x+L&$-p1*Cfs|1I_Y)ZDQX^uaLJCPoJMk?pCt4ZNFk155b|kz9PQ%$|2&`)X}N`f{~)>5O?z1NUu}hI#F!^<`=7{%W9a1w&`{H0EvUb>!ut z^sCD>9MkfL?ytk0l#dQ8$Ekb#e}_wtKZeaY^O>uB|l2i`X;z<&j~!|LR!1o(wVuC0dm*G<~J>$>ftl;j}G11iK1nULmuF{cFuW zgC-7~;kz<_DQ868QQ$^{^Z5*A|L~YCZhkjINA;E=m5R=hwgA}g$3`)J^~-8EsC_^s zgunr&lXrHJ(EniqMiJr!hG$dfOyWZEoST3|M)k>j7U{Z~y1*F=LB^i%@H@@rVpi&T z4d7jz^q@4zr)GH&YI1XH(piL`_FdjI71bDvmwuCNC`%?cuZLT(U;orgxUc7dy;gfD zTz|r;58mz~GmKd>A`c;UzXh%nFr?p`N*0;$RO;N2sn#n3DqZHC(UBg8Zqq59b9oXa zG}wkrD>w=O_{4G5_&ANI$7Y{f4XvHV54D%16P#R3XzL_yzqfS-;Sxf%-1bS;Lh8I6 zMz0vzc@RZxw2F9IP^?!Y3#V17=R-vKTqFJ9oR zaH1f1PnR?`kSY8G3_ z0!2)Wu$owb6_Br99A9?RzP$|k+uKO<~kUM|? zas}UnG}+cW;Xt%uMu!_Bzj*shIq-)(82r9&_$!VkyL{UEZe$3rEW}4@&ca`21Do;< zU!xF!r_D_M+=%F#3;0PvzvxXV_>cR;Q!pp%>JEO>wtc`kzocJB_SGePg$@dp=haOC zQ+-*#8*dCG&i!25pExJE~d-5*y7zYFR79@w&6TIAJGwVSMgJAGx1VP z6RTJO#2PNwpRO6V&nxK8yH>-SG{?XlvzwL{0W8fqlHGo4w5D>^*XcXO^arf;e@;02 zcq7J4*H3@XyhrT};e=rzZbwam&}$J)oH=4rF!^F&b(dIEZ~npiXGju}e+9N|>Ysdo zU@0hx?<{W=76!$+@Bgi+C#7lz~$D8BqtB&sigFB{m)rx>q)7Z-PZK8rP#umVnix}@LbU6 zKjrfZ@Tp@H2ufGv9gIqZdgf#09p>o3>#Z#9nW&tLQ8PLx_kUXi35{(>Ts-(+UeJL% zBC@3Xl{5Z%Xv`&^A#7s%nQhDYx2hkm9r1szxC26TI89DF@mz=x&AfTny3_5~9~oQz zRS*O`;ti+}C1Sq9KXYrAO=1oY&mtvUPY=1as9)z2MEIlsGAs7@~m6?!u`^5l% zd~H?kAN|d}%U;MXB~CeifHsU_m&27fF`W7WUJKo_tvB%(?E+KR`HAUrr5Prv)`QRx zHGn~|a`^Rn56JhVY)3$~2mKdJyENgbTIRKtf#W|&5}Y^!i{b?d|OEjyhy;kVq#iesE4K%fE!eu|~-NKTl~ zw@hN|_qGR)R!VKODKuSu4F(M+kf_L|NbE1A=8ez-4rJ{Ap{B3`ybDPT@8(z6^GL*4 zmebe%dFN_qM>^urJb4Y32oUSD>YypEE@lVU{~CSL=`?r8T*Mgh9;SuV!o29oAqIG2 zXFt32Wu~ILbN+K}LPJLix4__*ubNog5cc)xv%gCqfg4oHctP?xwtg4wj^gy{@l^wR zG-^840c$ox80Ttcl5=T}dGvE9CiaGF$g!-Gbejk&gjUk`i@`^rO8}mT>afwU9%*J| z-!&&8ifk^166{jc8}Py50C#Cv;+FWF14z(pm7zt8N{Tsh)UGBfQikpcktOFG6@;QK z`{m^NVj|l0!8e$k-OjAlvU1b3-}Ga5CXZSal>!pT2ug8&^7x+vrdzZ|I*D80faa>} zLz_0>KYi(D5}OwhlyX&fISmtg^f#dXj@8v!gxFoXs@}-sO~-&w`iAZBJksI2>vtSQ zAng4>0$=r(szqm3%rj^d)Yb|E2zAwpWNPlAmq{$iBSGciNt(cZNmb}|38Jt~oUdmg zu`bxCEdI@SvXFq&XL#X@oAG)eP8o|X7LyZePjY=HDXF$lKc|BElzTci!tHc)mz3=s ztb6hUD)#6>K9{5N3o zK~xp&bmTbRaEviX%G^EUmBnAW|7In3S`)79itFrS@IfC}>8GdE^IgRm@I4M#tx%Hl z%~KvqZEeYh6o$xWZS>~ZKimkXHvVmhEuzTG`<4~HSCl1<3v$tun3c(EApO$j9RyYW z5*LLb15!#$@{vFfJv{Q^;B}XH9@Svx45@9X{kp==maU!~6R6nM_GdEaE^gW7Ab$C| zRpHr=&9JmPrK8*JnDgctwa@^*?kxFT)F|B_1@3Ln@BH@ubI5N2z|oOGe!q^HRR)y* ze+^8#yFVihcB^T5fv{EgYVJL${`O-cFxSfjt)}v)570yCvTzXrotCzLIP0@eZi}wkTmY@0@SH{#eD`#cVxjrsC zz7@Z7-m?9EH0CJUQ#4an&u>|{-qc~fevN&dTq`HKXe+AQ|2#`7Y$L~{)>8u9N2nvX z`x|1x1sg2RmpDU6>(CwSN$fUm?*-#r_}&^>$b%#LRWOcAYd#fXjxPn)9h1Z>QPk;@ zzMncKakS4;sSfnQtycHjYKI)l_tRZy z$*(B?ScUCF{+AsK39kV!LM0kqQNr~eVyRmCL&;bYr=mFgB=0!o5D(Z03q7${b}u7; zt5KrQtENc;9ljaHCp_ri@lTDaZ4&oM$yE_7Wp3_nZ8}fU#!@Jd3oRuu@^Xl*#{FJN zP$Nmjd@?V7^BoI_fRiR%y3{Gl5P}FB5Q5xD$$%~dhgTFU8HRyPkf$(5tz>ce0&>!> z-+K&czxN*5 zyf@}uBtkVZULAik-br6nVRVeybWDotiWfG2gFyflnD9%?I(*(hfRrt}^hsh~6z0l4 zi3-0@I9u+`G-|$o&vKuHGzwTn!6eGAM2JYbVE|dhwIzVR!eUhu|dPZ(`9t(Pc3#mcuriL#{X z)|uwH;FazT@yPH63j@j@dHEl#(@XsN<7avhWXNvGpps>LoO;-_oTC|g#VdocU0h9b zvEYeW8tA>m8Wtq;z{WCF7JUlR7%6eQaRdjUz<6q|q3B{#PMWunQ{%sRQ$ z!w-NDc;yxEt)M3;QIRYPT)}yLwh6O$JT+zm`U*!HV&A(hRh#)5YY8)g`>E!Ywokz?HnpLsr)OzeyqosBaJ_ zzMj$2{6Q@mXBRk=NF%C?xKnQlk!$tyvIHv>S5^&Lv@;p#Z6|q+2~7_n>wXq|ygGB7 zTLi9zMjK}T5nGb|c+VC4zG2iyL#%fsA_94gV|l%kB6bplgCiHW2q^&95)FTWn(pu! zpN)3jmKLLaHd+7eDkZziOQY-kEkS!Ow(Ocz$D``$HrX!$61ZR+=bXX-IaQRuuwYp+ zqo1I|BQaK2*4hBGB`PdYb3D7~h8ob?)NUhX@-h_22>!4Tq|mP*{)GdH%H{!A&CifQ zBkqWIVe)%ti1+`ECQ3uTP^)XNn$k)k3e-F*2aR0nP60YbGOfq>yLAj}e?e%Z@TART zT5mYh&>BR#ib~O=g6Y3}D#A@d zer>0l+4?7mYi+qonE+03PslcxS+Gw{5TXYh$itz+;9|B=byYu zp!4?BxWQPxW69BEHI#@z{(keC%vVzKlxM7=ygw<=!Y<0XCO99JAGhclMXb0Q@L^obxfK1ev3AFMH$GG~=k zC2BuC45K;iYy+qwLyENW8|22VUQ-#bYN7fgZ+18H91VX0eKgM6Y-0-YW*T03P+m^g zClK5Yd~br}i$7gAz)C&bT1h8jVYFJ8zo~4@unS;C1VWqnBekEO>E4Uo+#17NqaE|q zV9Ls{!~!(?AJEY+P1n#{aPk52F~#hVx3v2t7ND#}k()UW&*;*Da)0@AjhZiNsr74l zEkj@1fE>^w)hx9%Y@eg2s&-(bjHD=Lu}A3o2FL1bBSA~L1O{2<`hp&BYWKol+okSX zkQ|WwCJO=F|9Z4P!7~3>LvMeAFzzyBG49H;bo;sWE;8;{k=L7|)$-dS%j2y+-e>@i zU#a;#uMedybnDdzIpWRcL^n>5Qfz69PG0(GnWfzniz=S(zzT5+E`9_s#BaPB*9_yDm8{Tn5BSZ8%> zPS_DooLh!sxnL>$_KrWWTdyq^M)SU6OR~t17^ZAxz?WPCD^S!*pM!_RQRwWyksBha z_l@2$IpUZ6|FK#V$3xRs3x}p?=uv@WLW9AL_4O* z2v)?R3@S~_BU(S}+aWN{+*>3(}nlHVoL6@G~r`%(hyY15Q9w+RU32 zqw*yXZ4Dtp`$DgzIMd(%#13VLd-0*7L3n@_9(dXo@6~mxK1a@0Yw>A!#fU*Kq1jEs zom#YYvPX_X43Fi-$I1*;%+DBHJ7o!W%|`b{_t!G!5-acb1KlvVCfrL2pedn_KTcc? z6sX^}YS8!|#GswMW!C*tv}mm|l!Co&Vlwhj&Tj-Av~G<;ABc|cTd{n6fL>PUAjJ2$ zL-+T(FN1xi%8E86EJV2<+NL4tMBS&{cHo}|kiIfVXVBiu-W_z$Gf;U)*9`eZD%x7- z02?*tvDwacbe2BY|DaZ>F+><=@n!s8OH)2>qILf@{kR2Q z8vMscw)fTM3zAFfP3S-Qxt2?5yUJSAui0Bq_ept-7x-~M33$cT2UKyDNOnsy`VMK@ z$7ObdM+M+FKEK7ityHFpN+JOx36H3{P+V3Xkh{D%JXC2<*U=9c7jNr{DrQGnVSPq9 z$|hkD`6E`{Z*!Q_L~w*Y})(C&S0lY@#8q+{SEc-74#){@Ug_XH^dP z%!V<{uzm!?VCd9Xxkg1b z(MW~_bv=uNF$O%krQczbxRY4f)Fh|B&8Z4)w{5z^%v@f(_=* zex6g}^6NX5Lm7eWA;RONHrPhskQueeQ`g>|YI|BjVnl0k=wwQ$(sHIJfCR@ce`D^T z*yZjGlVhx@`jY?+y&RW4hmMb2m2lXEZ7^szDVwW3d1;;crz%mNOVCNTOL>%_;g7{s zny#)8*s|e8$D)XspM)f;l1p_dAZ11b3jdN~At^!}5XvI!4;N;GqQr457wbhC;gwCn zr{uLs6Q?l{K|%JXWuxTyDimq;X-Bl>(EC0I=S}*A0Ivxa`gjw8N}og6Y8j@Z*!73u zeF7~Qjq;3WIP`?3H_5@@968kUTvq8X)j#?#u@#WjrX`^&>Z{$)zWS3S|6*9o6i4kR zF%GVfKk)OeB(|P%s8Sump($Gw4c37bEK(ElfK=nKMrLU7`MXwSR{Kf5$BQ#@p;6Fb zyRJu@u;Bs4PeQ|11X8l3m6|;QI}|#!d*|s8M&MQL8Uh~;dXpjHuCG>2sXCeE8!(lE z#9k4bXN&no0hJVW=C;_FI z$~fOieO2311GUV`2o;hDznqZ11GSDbI8aqk80We4evw?2BRVIGiUqYrm$6k#7~@y9 zGN=FMS85dTMhbsF?df_c^{J7$))r-GVZ>#_vZS|pjx=H6p1{(}5k&Yf=#qdP!;%2s zYAAtBH7dj4)GKT!+AHQ&dQWd=nyR1IopGPH_S&)r+{<2_4n3HEld$v%ML!rW2d2cf zht&4bXyxVx@*f=4BjyXIVJ?g27ixlYV@l3=kj|GFag6wuH+a!8|h9|5}(= zU4?tghp8i-12DBa0=fii7Y;NUciY^nzPveO=!WMVM%-GsPgU^w{2$DX-ofH zg(ch*oyzC~GaMw~*GJ2I+Vm1W23F^4VQc^cm@ZE@_nwF`Z7yH&>=laqr(g2_XGL06NTpKC_>_0)6lsE5__?X53Q@ zL{qkqkUZj+cr^wZ$$_K`3OK7!52PWdfSA6u`uBVEAe27MUjkc1#M;nalum{Kl`$TO zoAXMEF=4@YHIT%^uCDhPE5crQgVpV1=8~yQkie@&7Io(^Wo6IFpPo#wu0((hx*Kf_ zFeFN-iI;RQ(6uTG`A#lk{bWW1*L10d4qvr$0T%oAH-} zR3-FxNx1Q5o3c1f*ZbVdN4AYh{`KVL<=^uRzutS#q7RIR9*jG`e~>HBr2WQXaEB>8 z3$m&j9t)eprlWH!Y+>Y|Zh#@(`D0xu6MtYVXK*dN1;%yFpkl*)!E(djTK6lp5y zjm4^?G8xY&FT^8sj^`^Ua>J9Rw9T=@!Am8LsMV) z7C7tl#zkitDzlJO(pEIzsn=1 zga|~rGF|R?y%J8zWaOpdWza#N$lVcv?Xe?>h}u1sQId{2poA?L~@J;Wd^ z1NI;bG1u{UAk5i#4fi7ets8XMffkr1L*=eRQg#79+csC!?IPvGDXSI^ae-BTvP`+agQO@~%HY{X)V6VG zP3gkt5rnMAe(cATJrZ^0+O(&90rdbTFO-w7j_fo2J0Y~w6yAY0kZbbaQN*~MJ# zkUik9FT916u}Two&MmqYik)HD<8VboFJ@E~m#;&l+m?7hk_`=UA=SL{al*=C6AK4j z@HW`^mizw4uJ z6s}_nyG+^W(et?fSA34xe3uFjE%6d?i#}yX?sA3DwAgD8J|+r+yQLCJi^hf&_)a`t zz?=phUt8*kc!&vRCIW0@El2!T-Og6D+I*m^Jcp7*Ht@99u-S-Y9~EodA9e%fSzz@E zb=U9d8jm+wQG>Mt_qsUZSCpqet1P@lBC2zZPoJmYfp~4B(OVd5P0#8tZZebK+nQ>C zYW|==Ph7=uO4!#S+`8{%q&pcrjd#t-Fxk8|LwKj1MQV_TJ^Y~kyM{K!w`yuSUqA_F z%qzW%6$`R|6)ZZ1`S0HSFI-^NAA7rIs24P|IF$W$)^1S)OM(Mx7-baY%2l1tm(t)^ zcuh;YvaDn76SoX5>Uvm_kQGB~^Cw$}pIE-s|9-(syX9K#E(wHL@3|2PQ%|&UN!~e> zE8(QT0TZKx-tm$TL;{JccM$tp@<1mIE;QtC;kEkbKh9;N9(W1-SHySOF8g;clxy!E zGCxdd;WO30Z5tIji-x)V79`~SVH~P|>O#E5<^E-h*%k^~@DM+IWr@y(IIbAVsOj0v z3o4YvDHo1`B5#W5#@Lr;`uo75vBu4gk|bm|MzKv9n$S;V0aKmtz_P+;ud|4AeRUHjN_50n(Ox9f-hM#^>5`aU7|FQM<04h@`mcch|rLxyfO)41REDK@i#Meqwrm}3HHJiK_ zWmxVsMGv7d?X$$4H7AKJr4}PmH=})orj&TiWLH(pPZD&B|7=CY9Edke4n&6zZLcj3 zzgBnJVk__(m`~kp^+9grvX}=~C||D?(^CrO(<@;8uQJ^jfUaQQ?a{Vq*SfJo+uXHZ z*L-m1GN2d`&CslFY^Vfc>Bnud!`$L#Yt_>am!9!hVtcV4-@iI> z^hX4=;<8M09Kn9`fIZhV5qnOc-G0f*7Gar890}x~4@blLz_nKAaf)x|4v(oylhKMs ziKV9-v5#lKU)%0R`NWl}j#!Dt!r+R&{S69HaxZ~Em@&GFsXJLV0bZvhUE_v~dfOpc z&}U0UX7Z-UmCfGIIr391(&FWb{`ZKVLV3pypiPEeBm5Hw1&i!5zu_|PH%;^NO(kDQ zv8ne7Cf+79x~)g*q~j&_)2V0T+QXta5%7eiQ7xaA4ckt(Idf_=xb1KZcMZ!C$Kj#) z$VG+~{7sV68&F^1ZjCss&laj5qKX@ILCA`fZ_5%F8361$KN5{|qr-sQUbWSw4AVN< zj*dAh(?}>V^*f7f$!JLnKjlF?_c0d&f44?<9KnVYM@W&s}5dQO{?uc)v zz!wz~^mNKe7;niR7hdI4LF_M$ULUpOfTXk9v`%G?0Q!g5P@(qRhK~B@@SM>%MkfGf z-$^mWx%SjM-4Mg3m?Zp?EtuucI~=M4i#j%5IO_iq^$py0wOzZh8a9m^H+Ey&wr$&X z8mF;s+h}9kYGWJS;kWXa)GP3tx>%OmfX@-Q;^pd&I>I*%WJ_#6B1_o9i95#&; zh1AO+oaHN075Xlx7Ts7QvL-jqDQx?`99G|s^HbU0m6B-N$32y|*cKxg!vRC5#zKaj zpIGV0jjFccS>+0(aCd`~@|2uCB&3->CdK&ojvsHECFHmQCO2Yz5u-MAMK;_m}KylH(sI z)tl$?R6p~V#t>R~__Fjk8K+iOCjz~Eu;L+AD#Ont#2#%H`SDGG->hc8ByK~L#{05L zd^SW{4cB-3SMmK%3WnaK@E(Cyg=Eb^Gv|FJXU%IwZwBGy49o0>KJ#j?yBl{cg}J*I zw|ck=x7oQ-_a3Xe1KTJFq}`xKaYjkXoc1obk3jG3%b%UZ<|3U+rF)z0=9(rZL(~P^ z!$&$yL72IuxegrJs9s}o8JpLvEVdfhBO(CM!oXj1VrMj@slGnM2YpfAqW5N#K>=6` z+_>rWI`s)k0qVi8J!At{2$mb43*=-eu>`7Bk^liY&NXt$mQVWN_5h!_4i*j1X0ahR z7FCQ$(WU6)8Sw=(gd7T6E8?4X#I8C1a%Xz)b51O%KTP}5+f%eQ@+o^)2WuPMl`9rd z%VAznsO#ig1o-PNf1DjViKY6)bprO$Y|{gQqR|OMTLG@Vpak~NzQ-rBahpKs!2;kA zPKQ73tp6siJ%1ZNre*16pVHaj*=#F)PiYqHid~GAGZ7{bZ$Z|Frr=q-4*BaqzuY@7JyHWn|G_kvza3-}*mTY{SO!px>Wm{3G zn{UHUVR~>sd^SI!m35(zA%81b0Q%ktvT$tLa&!=52x zIN2K^q(_ly?kz|eoIF=`00F@x|Sd-RwahHox6 zZEtJKagUl^u0Fb_`&$jIdpiGh95?t;9(@=0v4DW&-Qo6G&?4&LATLo(wqX@(?H3^b zn2_Bth;c@XOZJJ;8s@6h%0YCW*3npb%0ijWOaB@QH(@ag{qe#zW_|4Y^ZEBQCwno= zF$TC!J=aZVtunYXqVwxrq<~G`6z7Z{|34gEXm{uja3$<=m)tY=us1Tt6p*d+eiNV^dKI21CZv2-Sp?en_)Kb@BSifP9BxetGlQgyReH;kP%%J z?X?GRH)N-@<3Kb-B%F(&^D99#aPVwoRfFRI@GwNN?9LTi;Jcrkw7xiHB80bv3YHGh zvC!mrUW&8$Kvh%VJw%J}d4{YGO&Aki6)(P)!_f2*c2@EU&ahQQ3zLpxe`TrRtJWV9 zN0^)`bn)U132xhUvnK+xeoe1G|Cm3piCAI2Bfd!G6O17 z51QU%ol>p0T}Jy6rgJ?IMIoW9jW^U5{EhqOCshPwSwrRduN>9!bO8W6C=d>*K8U-V z9LuD*sH#lGWKoJfT_vh=f0KbHz2Zz%?mjU?g|3K_aEAw{sL3Qhk3YKwF9ULT?UxJp zYiO3)KF@N_XMP$XhG-8$Y+0li=vlx-H-+|ij^sByVh^^aOja%Bo_Dp(!Vv4T+VG8s zZ5));dJ-P%(j5=a!aCrftye)5}g1p z$D@xwIw;PoSWVi#N7iI7Q`JzQn?TJTy(a~nJ}0FK#dnt)jfDfTA#O=yDsxiOPoX|g z<{~8e^Fb@KnOz$E^rPJs4mGwuKHwq1*=~DsggEYv5gK3k<08}$G@#ma!{uc*aa;k3XKWdyqujla;gA{hh0h)UzupId4s) z>0{t_Zt6BWp6&FlQ;M^wUt06d-2DC>a3p=gDzPz7h1Y)U?lk2l?|we}0WIaHXFng5 zbt8K}ya4E*ka<``(rf$k!2-jSqN3Som?)0w$@%aK*9*;r~oE9B;%@E=T@WDxcYpU(hR*>$3YGUqel+_M)c@Wh(cgtE4 zee~P05373x17+$LI)F;!FYg030?7BKWzuK#3PSPZKv|vjR8J;<5lNWiy?cA5CFEF| zmPj!z1o?f}M7eqm0S@ld=TY66kmzCv4U$Iq24jt6ATkZ;s;-p5aDEDi2YOAarFbQ0^ z`gZQ{I2p@ZMjaHBPZ_7wID60kfr;CwFmLSo6+Vnu{`|fa3oV@{y?VxVxuLhIm#(*Z z-F=A8U26P%sE%NaQn?s{am^tE zT-AJWFxpKsi%R1n6kU5^Nw;ajmM>uMn%N|3R@pQw&)TI)6?3{#QcZPJiLL`f; zR7SSlE6p)|U(#xBnw=X*2ncTvKs+PiXn1m;OxTvCBOvmglwuvhCY1GgI z;>w2owB-&_WJFzqOnql`QCMgssfBUlOtGsScXFE&gFor=gXYbh80*E2`b80Z;LZvF~N?Me~(yhE#j5N)uX5 zL^Df5zzSb;roCu@HAY%(!EIPKEBqS@d)e&})CI3ruOBiKZ1`Np3Eb&msAWci=g(v8 zwZg$4s@zOl@z0*|X4-hke5;P~yyTMS3o>oR3k-AN&e%Ebf0HCsEuv$CvM~r`#sGy0 z$>$aYQin!*c_OcPB!Gkll#CK{96|9IU6J}IGAx3aNF_yJ^NVytk?j7cYS)N9Ey)p> zAh6KJtw{<9feTaR9}Y`ZT=fpC&v%J7ej3ano)k|U)htg~9+oFEs zv0gP^&PsZeOn4O!zhC)w7*!LknEt7}-ve+#L0z@Dh^H>GM!j#?B;MP!+Mrxq@Mi{d z(<1Z>keXe$>H}@?iLM^a(KSSC9f*VIaEn*;dw$+s=lch(i+hb;!kIL_ViPprYtGQ`1kTZE+*@i3NLFIkPs63Pt3 zvl8+;%Ke}6F{R)+Rcl0_^@4psKaInf93h3i04+77&G1|=(XjzpM=Ssp0Jn!YGWhyy zWH6og5_|a7b!~J5AOJd$vUfM==8TfdbUnxPzJD+PV~GqiSTm&S9UDoNJ-ybyq9Wni*EMa8-MA`*Q6 zr6{Gx7;443=RN?+Y+3Xn$u^D}o(%iSHRm?{jaL1)0Frq+{jFAq5Pyhida2MSM5P2D~6DW`iT=gA3@b&E)l5<~i7EZ67wUSwd<;kHQW-Rc1 zjMdNXcU$$DTQ!6yUzpNMu{sZ1GY-C|JG%tcIe-l; zA`+5z+izY*81wjg+%Z=7Rkh@R9CGh7{$*pCy>~|GIajX=;Q|uThb?PKcMuLS68Ynk z88EV4!43t3Aob6ETLT;xt!uWcv5{jJLa)fDd#S+BMgg-P%WiR=Qm(Eg7k2o!0KreZnu3V`QU78&R>K(D=J$cJ|>$mji{xqbe zCl0<{_40&~+vIFbaSH;U4niqhS~T{s*#;Ukrpoh2M{6~+PJik-*zxCjLhk@zmKbcW zOuF);6(IVKPQ)Fl3RFx*!rR76hGVm6gr`k?I#dg83g_Ja-Tp4e7KO=#sVmmJci){l zQ9asmdGEBd-drMoI!U6*n+Tm%X;it_QC?oj0~(5==wT1kkfn%1IhQy)HW`&3VTGkk zv|l^aSx;S%{2(H7DbYGLl+;U)8|27pSoR-5Y@1jMnrt3X#3sSbAOddiXH{-P#N@SA z&0psICRzEa$`9G)RHkQQKXtz9R#PN2;_6)_nBus$lVA0L+*26lt3?Ym&cbc#mZs_} zc^}u{4T?;zZE`6e)L-3%j#(wLnTNjBEX+fWR_&K2HfYcNZJHaPO=7-#Ni-245af(W zPd!_WD{uOLnv%WxEyWF1XI>K9p1O}kRnZ9PLpHLx2QQW(db(;n{zwH7HXK}bo@Q># zSth^t;JqyT>FG-1YuMI10_J`z50dWqGI@F8Mz5R4aI)GD{hChq>L;42u=Zs&63(_! zHV*X5h5fP6hWs$)$h&@uTB8M~-I|&%D(Cr;D8qn9@Pw~M@JmZ|I)HN-E&fp9SSs4Y z=M2ePZRYCI!aOK2xNr!Om8Cz{Js}T1SeG&XIng@piZrD?V)NEu-s-T%!}a_k0Jx~C zSb%$33zxsx_)fEejGRq7KZVql{Hq>A=4KR$W6(6ki#3aii$b>DWT#hyNdE(`H<>`nf1MCVVYRghnbA0#H|sY zx6d1U))nt*$oXZc3GcNE3m00=xoriwT!MnMxAc}7&CG%{$#)G?#poGcD3H!fSdtQB=jnY%uhqmrEEv{ZN&_y_Jrlu@D*|qbZO>d8# z=aVy6{zyiP_1I>g(J%k@oK~zu8Vse#qfJRZ*r=C-_6@p0O0H3ps-|)FQL|LqxW?u4 z%yv)?pkUbaCwec2fDvPOuTt_N%c*fgVnw!(v(O=@B_)rIlGU##oIo>~1>d`xb;-dL zkbdw94~1oNF^7`R%rT>rs@0qhx^ zLbHTCYTX&thh7HC9xTumG`@|OfrsZ^Tfl_1l7K_b+IfhN?+OtR`ck&0>v~vg3578D zp)qOAS)5iI8mZxKoi@C$-P#Qj5xY`q4Vd_Rs1dU)!oeyu#4rM*rrdJW`&W^cC!$T= z)r^8P_cuL6U=EGrEmO4HpCMJ$*0pq09lnU!a8y@DqLF{WulkT(4GjX|gMTp^66zK$ zL*7xudqBb#biQWiz~DguY6hR`_!Qu-#< z6o5EhdaCH*V@vZhdBk}9rP(MxKv{CkOnmQ;J?-*~k)eSqm2m{#Uy(ZADaXN^F&lA; zz#BMS(n5vDUx>9CQqSeuTKI3`*q<%t)Vby3nALsNR1iyeWZXkF?p2x-XY+9&OJ&C@Jujte%kGNks zduNI9+cr(B3+VZN`A$Dl##5HR%9p6v^)k zPYeNCNnrqo9PgUbOR{NVZJxu=SAv;rt?#=>!-;*Icv@s%N534-Aon)u2oQ z2{1?Oc7e~ea2I22(?yvil+d7SsHdO54ts%<%L49`fSH!z-IvAZVl&=`DNR+FK)`Q zr)gqx$u&KtOCROo;`2?lLQpqk^)%j!b^@KQ)}iq`61J;I5e7LbeOtgRZwUIHJP%pO zC$t+atUvXsGQ=d9${2soqx+V!-pKzGUil{B+=L~qD#JQb#?}TbgjQLFFu`q_jTS+9?TbgYp|=yCAtHC z!Y50peG&6YfTg9x!WC$DprjP9_8i8x3kb1R>{1gcTf^Ob{b}pZQ!LuBz=p;%;o_%R zvJTqOSd(?G0tdkCj&juu`iZyC`quug-}R%3wYN}MVe5LaEP5GS0sKCykX6|czQyxd zK8YtV(9st<-f1w@kN)>_&_-Zs8R=%FMrv68n6<{!htQ6!_H9uWkj25DVqfcAmSU)B zEk5N~vzA=o4YI}vA%->Tiv2>eRkc>l+FzG*lrVy^Z%=cEQBi0 zbCatO^8|JTcAtV+b(v1)uZ_{+X<|@ zC-ZX%MFAG1RLgpef#N|Ajq0^{jFjUu#luy_$^;d5M_G;ccTJV-Ae9ZEMoBUf7J_xz z+b*88!BE@ICg=zNcxA5+#+iTlei2s!EZU=CFb4wx?Ub~w-*8>+^0!_+oq*+Ix5}8? z2FakuKOG9 z>r<>Z1b)Pxed%*|bA^#$MH*s9RCBvHORB(0vv^(BdJ)dz>&9nl{b}3zYlsa;zYpJR z`Ue4c2pS=Riw^tkIWgz{=`P26a__VwV;5j-b3|q;Aa2Gqr(6?wXqC~vvCwV@0GAn~ ze2;+qJ)XRcacZNJE=`krHpU*_oy$g}K*Xcp7KSHTy(HY7UpE`9mmhE1HSV;lF?x~v zT@-tt*PKO-=wEs!vgqO2TUOdizptR`d;;Lq`qQV}kcqda4h$9FJ4L<&FT5Dy!4Q4f zJj|$w0;wCZlG<)3kN=1g!u1g$*Xrx)O2!i!luezO=UNiApI9qpt%_ts+sdc^Q!|AqtTgWLw=D(|S@W zE60cm;$`WGLkY1{8FmtTNRiaBwCBG(&}UDwoLig63Ma;s8y{fn50K$T1EW4ai#2<{ zYi@iHOrRlOt<_+1jrsLqqVi;AaB|`^1NA?u;rIr;I0DaNF6sC4s3~AT3PZgr;_=%Q zcguy9Ji^O+oHJkgxe&0hZ(DF%>r(CvSMfK0`rR8EUkdApZZ*!9PE*g%l%_ZJiOsgf zC5zE42wHgT>!+O`m$E*lqT*1m!tp~Hy&vWyrYeecm8xp{cwljb<+2t0cnBbp&Hojm z$I0hNj!YG-?)e#^X=_e%pPZt3YZwg}NsIv=)|M6+_HHmsl8GP`Lcs&UVfGH2?3!7+ zjBxj}p6I_|72cAR1@Qy)w9jih(L$5?b>Nq4tv?y_hi>F}Xf2K(ighWj;h zb_?}hXxH%PVz_VPgEJS*ts-<7CuU7+R!Y>e<;&lAL6&aQt3JOVlMUFH*$KD0XqsFG z)bzI;gHJ+`V1j$$u9@;f{d4$jo9%H&)^s$h-pq(_kNGom?z;l!hzanCnB1gm7IqkM zC<4983v2BR?k-*C!{%wjfP*4x!(P8Naw8=6)wP&}BtlhZyf2S3IQLdvb#P^0BGHtj zjPry@t&z_E=}o*rDi+r$vx>*+#hzC=tbq-)}j?HV@~{}#I7#FZ;wlI#)4|T6k2XcX%}pnSRg0$Lya1bj!e5pk91W`vAud!}rBfKe)Y*SR0Dda$RE{P&HvJ-2a1$)uWoNB)YW~cR>gPQV2Io{o4D*=f zR4HI9XU}Ex>*_a5GTeGTXwc5+Ugeh#IRwq3T??L=h$_c(6u{4ZSbyintJuYyT# z8^`$#=cdjExoFFz8f>mZE{+Ei(z^f>459%n0S`dL1?+KEd~d>M?YGb>!5;b0-WmzR z5TQ>fZ_4r(FMe)5{rGw#YefioYpmrf1!FzV#ihKZN7rAr)!n-Lq}izxIKLqIJf=x) z)~wVbk9k!Hc-*)&4Y~?6|EIcL%vLz#Zvc{PBhnDTj0?iQNJZsqE;5yNQuj;~Thun+ z%%hE|UNfkTl~fHd{5=4yC|{qIY~UmPxmfm_o^eh}lfS@e5(@rDkOvQngFz}NgJk(I zgMopo@?hZ(ID2U-r6P&GepLgU;;%8#q_?|&RWI7GItH4b{< zkYZ_5m*!W>{{`%c>69M3%CLlk^G!V+Fgk!O3bON%1dU3u!S@gq^|t zVJc52bAu>w8frZhi=gN6&wwzxzN$4I#2)?_7;U{S2+(mzs(!m|ihASCDiWoCT@ij6 z&H&|-To*+WhvJi+1M73rQc5D*DaQI`$!eNP*g-F+DPMUH1Fs)n_k5%x&mUjk8)6~) z!3@||*3_!##`eu6Y^*_tRu%>*c#ODR&cV z(ObpiF4bhkbmp9`x8Xi?cCz+gndVJ}sg{m@q`URAxqpo7rqcF_1rj|anW01OMj{H{ z-lld^Xs9rg^s%uG8}S$Zr=Xo3K3)5U;d5vjtx0$OC-$noPT0Rt;piw8NHhYrlC)!~ zSrvvcrhp&58*jQq?mmPBYiY= z25$`r|FblP*D%?eJ*3a}Hj-^8Dvg1hGM`Q}UWhS4HA*pt!bAdgb$`3DWJmlLY!uOu z`~HTk&-u)y%H*TuHTdQP<^xg!TT`G6@>xD#SKsemqsflnGy6(h!0BB=qfA8;a|(Fj z9?Ybo?tYCPMisPw!Zr+8F|d_w9vuVd;vanJdJu#(Kj=EJ65vlEI|(})uI3yPH;<}pHdUhi=0q;AcFw03@99B9Zexq*vvMLX9%B$O_Y z9xOt~0^*bXPt%7qtW(G!JTB8>sL=Wz@Ne~*f~PR?fQP7|ftoeXS9(7Tk&iK65-^`x zbx7?=A=Yxa0%iwG_e-_CKlrJ&laVi`n;Umx_0urc^Xt<5`(Xj`N8jLlYxNHv4=hzk zkBS`|B6TNmF&dQU_zzAg%o}Cq?e}6ECUf=MxBW@nQx4#1IQjq_8G*JoldV$7+>9AW)a7v-{h)D!yUNY9 zZOA!KvHEBJv)E^Q0EP0m&kUvR{y7!_`Z>5gL|x513bNq(w-i8*a|m*f|BtJ6U~m(5 zbZdaQ3_J*kGec$z_x2kIa}M*Cp%T`()X<#FV7CwjygW#cVN24tMy!(Wih3~jZ-x15 zOuAHRr^o<%r*b${A<(bw})CGFn& z>YL^R2Ay|F!crma{k%Uc?E4Ft5YH^Ve8tmzT-OTuZaxP+8RdPiJGT_8KJm|EKnFwu znKScAmNAiPmWE{!o;YU`eeaSBA`zRq=K9^+sEhm0!upG>7SXXVq?E-}SN-%!VEnSu zkbu=lZVUBzkG9@EvzAVP@CJfSBe+Lz4F@}r4=8#9ewRCNgPG+{zH;#uaT}lEJo|W= z-Wn~4$p#7pH$hOA}EYJTj*p- z{~^l?@BlHROE3#rkug1?GmEd~5fYG)J^&z071;j|5Jr{Zje6Aqp{#TT62oHnZidfJ zjFFhD*MivMz{e%AIAcGCsi$yPpzUtSN#y83D{lt}L~?a2s`cF~sOXllkI% zA05RFrJ;=y^JKQ4mo38~ft;S2Dk$60R+>&_5$@_otR?_;15j{GK!EtZN@s!M$p!7Z zuBZIk!I1gl3G!{6#dJz)99bsyvoXUg9@P@z}kUpBF`{lAdWzRuE-dDaMa0ELPj0m1FRXXNreyQ zRXCb(x;2pTnvAJZT9ziYKP0m+0cmDnOL;znhhJH^vr^~ZN+Nj*#;*vZL%fAeYl{G5 zGDu5n>L%vdnce9hD!kxH7_LWYGl1H70t&>$MZ4yZ2aRWx9Wu8Qb55^zv~P35bpbHg zu1D|ROteDokXA~ zQ05FihIupy`A?+91tg;G!*B?k7?rO=vHqKxJI`TX)elL#**>W#2O$~C>`D@32w>#G zFlD@>EOv~PrAoJxc|82dOGO^-BQJWdUf!ezH6S*e;#LrUp z7V*pt&!b-fNK0X@STI*+dGY1seTuz5;MDRQJi7Pz$dx8V63%uC#zpcPfXawXF8}m> z$?HEaf-KC%lKxO7<+ zRjKZ3h?L*^++MPf>$0(sE;N{i+*a-f|HP(>Ox}x!R5#@TKH+VfEX}v8O-=~UNpJ!% zK0KRAvfjjw_C0f#36|+QbT7xUx#@@Vx~eBRy1(5Kv>pR^pB^W zwaCzi?;B1<2V;i)s>RV+tL5c~$%o-Rv;ShTU-diA!U=UmS~B@%57CGZ?j|K6*_ z)Fna#jnDmB+Z;L%b#8TJ?hrLDwuAATj{Vb{WCek>z&bGkD^qNfpUx)hPh=Ypc@FP4 zbOuGmp#luUB#gmev;?$Z+FF0@h*vHqoGvohUL_-&>u@}PWR?ld-TF;<^^=};KCIhL zXT54ObUoEa?z2yw9pc9KNc23D2e^3!zus-gPLBbWsdVx-3;u475ZxsJKK_3;DKr?y)0x1HttD`?+9GAT|q zk+$ey*z!d6bUnCWzw=z%=>WDO2%GBIlKYbrE7EVFbV?u)m!^47xKKXa8PAa{iFH{3 zp{}*2p9*4MQu558Hv6-fbxIo_+_`wuVial&z+KZkF{u5 z_g}i|VcGV$t~x=sf^yDVmnxQPS-dC8a$$_dr2Q?G+Grq$V*&`@Xw{hG%773q2!@15$t{(*s) zaln_Kv3jHgA%yhurzTTYB0{vVGjigNe>gl;|fa0Jn?$dyRS2n!WAf~Q6Fx`t{t};MZ5G& z!f5aHR}HxOD8kzN6{!5?g7@BB&LlCS7_EA#kk=X%L>lu5Q_b|4UcI(6wD z6}6cC0(HWe=K{`)@bZ(dO4*faNRV?Y;Lm}peJXRyoi}z{);0&^4Ec-p&3(TCM18{! zX_&ZYVG9P~-A9O0W8Vzt$138-HG-SCD)U=E|5KeJ6V3UFub`}#q5ct?!YO)FUD+$t zat2X%x0I1eY0Slso5KOsIhGUY2WrdWd>VN1`V`nKng@^06qY50ucH51`MM%e{%7U8 zHH5?kp7yA*%=%00e@HW&t=ub*+HCyvYVigiX;$sG7gp^`8a@>ddG!loe}4v<@lP$4 z_odsxLEgaj)!m03tK*lHy-vc- zJEhLa1JRxhR;ssv2rcXn^1EFR^`GLYn$?Gm-B>Rlk{$d4M- z!_b3ctwl&^T&tX`kf(xaI!CX&%pZDx)A=@8Aa6-}q)u&u3W0I=oJnc2zniZlE_tbw z&80+zx6`w1!(XWb6~V)nm7;|UuoM4L_?OTy9t_xsm&pe`#&zrxL;B*?3%I4vuNj9Z zl|?b(@|hPD`UTrAy`@f@k1oCSbFT&-m!U~~5Cc+dreFrv_CRGHv`el#!k(Z{v@QnlDWx!AMV*8JGuT<*A7(Gq<@-O4oLqzJBp-=lKKl;`4^z%~KCj zUyV9{eKz-d4QA!tul70i<;`j1fGaX(NFmeeT5#Miy}ej0X?4D2(qS;89cmU=RxQqa zv_CaV9Kms~ZgpR6Vj)J=1qL2>jF;hH2>ecAI210f8x8*z!ZFSn9!MD&+Pc4F95q=~ISz zTzg`C-Erc59IiXPxvRez`xv*==dt6R(bbD8u#s_`-fbdfO{?nZ-#2hdlD5D#NgXc< z(5PxczNl>q6P4ugg3Wb55!OadzfYq-cj)i!0(nd`^-EVYnPc29N{dj~B&xih+1d(# z5Zp5)?2?r67(d!_n+#m@9skH8!m=GzlkeJ+=T>#jIRgzUhzZYzHE|n8{n*e^lL;cE zK>0)OC4$Nazt#7h(_HlGLQKD*=nEd+Gpbhn`;KN@CrRkq=fFSNzLjwL)0Y_;>K~zs zwSdXxB{aGpgS#uIab=HqxNKb>>j~r*!0ng)c>jIm;9Mu}tH@Y9N+Z>Bxa7j1hK%*& zBd5QnX5E5CeJI9 z*F!e#79pn(OViK9p6$HaH96&RZ-E4R1v}{nmv$rTp53+s-L=>)Tji<1OF_o#ogbxV zrFbEHe0dJ*PRKxBD`H0=eUn`%iZO>#{t?D$dovYv(CBs!1s>p>&$KRIpTs3b%dViDmgIv-Fbf zxo}^_VOXsZ?^IfK@t4nMnuT-7DD}T^4=mfC0qK#|9{p?e$GAp-fRvWipKn0We2;J3 z)p(Ng>|H|lmrOaU)As2nT;~~X$>njDD^P*>%fsKKa$L6kfP2U~^qMx?1MvW45d?`e z5rtyDN^mgffKb@cTe^#jtQ}1K8L-XDB!%mIL*B5m;sCtvnD_1lba;n+#J$W+<-I0| zr(~JXAi|bxFW(6m>k)P@Uh(ogqCP7IXB*UC7&2Vk_^c0mjs%?Lh*qIp8oOpa+VLol z)@I!2)vBA{GGlyn0*Q;YuEj#^=^xKwz}OJYi(sJ>$XJW$JYkhymV_u;yHH zI9Y*hJ;`oHg@y-LH7&m#DJvb_Slw9IjWaVLvg(EDQ`4K^<`c4BacdYyQ~>Umy3#R0 z_!Z25yck#9beO4AnJurJ67yRZ2HVr)mzgn`pybA^Q{8%7(OE>{H`wMEo>7GEzTPC; zQ>P(JUw2S5slBD#+yodA)DyieT7aH67(m>Gu6$DA^;*X|*IHBi0nlE?YicUBZH(0G zK!rZ;lDy))KDU9__g#iR=-92gcOcQ&FnO0j>!zlm&L^5!BlqDrP`=0 zYY|~p5|=905qK{yw>(%o3xq%Z+X3$CjLo?b_vo9jiPdNESBh**3m>^dsJ|9hgqeFU z8Fc2BQ2`7y`*)*QN6>E=F6ycB`vq!Om;axn5L$BD9)P5*m<_Fm-}8PB#S`e^b~0-{ z_Nga#-zvpDs=W5cF68?o54MzaB&N65YG!T*P{q?xs_DwcMYoFnks3fm&JWjF;{7Lb z>MSf70Y-DS=})z_)lPFKyfu#V2^+BA0Z50L^R3G=84#;9Z@acbmei$G$?=y$k`d~K z=_+$plUWpl#$;{lL#yGCfbxf!kay(qF&;vpF^-%<3KI*OU2?+&`7efbvG0*?G6+Yx zK=UpEu}pR09}mb|1=ND$S#(cRQ{UB;*&Hr^!PnC&Y^Fknoxl157dM!1*+ja%Zi%(% zQs}F1k`fz;crhA#EC$KD? zpYA&y9W&szJa6fMt3|j2aiIVWA-sV-<_+cJNZJe7cbW%RuU@vXdp<-(+C5h~efYa> zDq~sW!`NkkD|tJZ(BTfztO|v|H~n>)xs|Jg+Ipx&Ptlf?>RU+MIAwk?n~2A`I0RBQgLh>F z$<__T>u#?p6^=1`kuu{yuD{KjV=_FaxhC0Vpnzc=B-|sHLNbQA8;LaVo;Nl?0+hU~ zJa%tv?pyUX@HR2SPj0bV6nzq{Lw;7vs}W^qaX{&Yk02MoF(4Z{Khjt)Y~{!hTAR~0 zBw2UIYreCR`1rlLYassFeJih2XvH_(QPUd3GoorNHIb$LhGc@jqrtD~R)EkA7F_=c9a9irMv#kuc{;kF6PF$?d0ErC!!IkDbIe)(?c{Pu+bcp^*paoBN@bQ^|bOHadq8V$nl-8h>|`=r`;GSb$SMOWRaOIFxwvFL4x`NTbs zjI3NICu>9zj^2E{z!loZq@uy3a@e(JGFNMXVE9}0S7SC+(x3iHRgj4LyL%B@AY?@H_iW$3R_Ctx4|D7^ya`A zzpGhVT6Y%uR~#H~3VVU68465HN`YN2I0ao*`Wc1}$Vqf}5zmco|JjIMyB?B)?+2n< z7B#6xcBCv6{~ZVgoE8BGe>B;-o|z=b^-5RW+(A#BDPQAco&3ggd(Fgi+@c~ib&1q_ zMELXUgaM(BQoZ@N%Q8s0XVX&;VWI4TemlLeBlF!d;3Pz66lwt=eQsUFaK&W7blP0-MvD?<+ zx=U@!?TcmhM5egIhi@2nKSrIF=D$ji0-oR!EQ`7vtcf1?=xdmfxx^6rPPZc%q|H!L8TNms$TBsMEbm?NX7qLC`m=_6j-Y=pBr-_( zHSA}8xcu^8)NH2##z1}zYBC6qVFlg(mqie%>jY*9Y!Low8Xcg#{!=*qV{LCyjXeSs zKmfSej*x}&IJl&~fp38WRP)1y;83K?epP8w*jNv4)j`Xw1r5x^3&-o;q&8AZ49047 z+A@2Py-6;^EZxYd5aaOrTBwYY45LwrLjOlc^{o_IpG}>rgde19D8QPD{v_d$0S4*6 zJ<2qVWMVzW8}4R29-<9PkKBMxpIKy)mG|{VQ8`=C-G!5arpLGwbHUy1t-HZr ziRYSi)dS2u@XUcRltbyE1G}^pjJ3cBs0p}07b7^V-+}V&?Q5!wbV}4_Vgmk-Y z;K)RHRhvHD@#AbFo+{$RW!@oNvAa1xVsW4Uop_FhCFqb_6zBNK9uq}O!37{sk z$WJ02aukKF0LY0VccbXxfi1xJ(#33T{Y<7!ujJ(S`Oxn41Wezw!8yCPNHjBme#VVE zv3f?jGb*)p^P{~Xy4n^R68>tV!9tHDe($K^wbAP*LN<#(Y+O6gkOo@ZCtH-xCH ztO7B7Iv=C&@g;?#z;2S~SWHC@XvWxNOHY^!Gyu%=3JrdcVqxbb%ZV;Aa~@{^+!RCS z%B`_`6O}n|Z5TapO%g9xAG2#o;kAW~2A;!Rp6c6>+*!}uPZhP;VNzM_TJr0G_xDHZ zB*PvfF=VXRCw?t5V^Y4|9U4k{b(70%o9gkGq`>pref_i&`B7MBCJ?7V!n==vi*VGv z`Vc$2r60v}$wt+*-{ul~tKHybw|cBL96}3Jj9j&ntas=nS@+yFM9k)0&D-pr(crCn zJ&9qVfx&vAJ`c43-B1GbwWY&-;;WVeAD_g`01_*rn-X`27hp&OU&)9GzeU2P-l-G4 z??XZdJ$CN!ck)!e%aONWJ_B=>?fJg}?^=WtQEDg-E!%%^TvjJ%x0^FH-?PTF%1iWr z?tgC<4)V67Dw23C3%taBxz8A1?ykI~2hfUdGfbvv&FN{at&g`x zY72#S9+pe1VP;3xEbF z09}ZquRQYKvS?BO;zQ9?vgz#Z8O9Sx0Oj?iUw@9^3FLtgs6Sm({`m$+Lk;M=o{|6d z5ui0weM_xcRfW@;;v3sjuqKfb*(R_Z0|>kKAPb#RhrNFVSIq0Yg-cPU!n% z2js7Xp;^y7$xF4CHss2(lGi{?`uv=krWtH_!S z?J*+)_KpO;84%SCfaCY~=_x;V)U5r>_OW9ZYSn^@vu#Mj)wy-JHv1+5W{d)wH>0E$*`)ibA81jP35JXKT$v`6s8whrc?6rWFL%GD64qJX7Xr4nZ5 zN|w9d%i;O5EW5;%fQ3pK5vh4h63}s`1ove`0Y3V2%P-D^X zs+g_3EXn4<(0VFNu@?dd;P+JG@=_)HBQV#kl# z%*QPxueIhp$B`(^=0(GjI9M>e$upJ+V`COH}EeKPpuQ&)zUG zdafcF91A~HD6`0lTO@5Zrdg`$Ewey~$`Tv){&0M4v}@(jCD%6BU01ddPp*YFk}n!Zkr1{y@qYNCJr%1e z&3^8cKR(s4u@cGx@OOqM+c2pXEIspCNoegZ+_Z-7x^?)!CA~0vY1K)hfM!Bja>pJikKf+~ydy*d4ThQEr)kipbmj98UNkt^j)~`i}?I;}zmi;dS54 z{ZGk!L*sFxFkMF8{M3&l&`cIz;AM^^gXU>_=v90UNfH#$R*xMv0vObh zgq+LL;rVkVo4Jbzbjd2l7bmzloe5k`!UNU=#en8ibpQ7|RFb*kkQ4No*>Lve?uch`g7S+o+(W+v$t;gCJ`chl<{q6k)L_7H_P+VK?33h*W!Bo4XqZ1t3D>3C;h=^Zoco&Ohn_Lw4;F6ydB*?@`7%J`2p@h7qXKqZp33Fkp|}U5pD$ zie9y2ra_ORs7p49Hc{WcBeWcs5ZN)?VgWcnjNb)ZcXBGSM%4qKl6_jq!7&g_*Vkk$ zd*iJv>wurv7R@Nm(wjKdb;woa%P6E}8%B8+9kv|$uKX5DkyMb;HiLw8kkJC;y_2;K@{eU<2%}TR z;tK*;yZ>6JD^Y?!%!H?5oQW`B(@_QBqC~e;#0S2AbC2d;d0aI-M_uL_^a>61sv$qn zEJ)E~k9SDU=dD-46%vltB{z4NV~e%8QL8NGlQRiG0EA^V3J>#Qy&dX-#MQU^vC|$N zjRvwHx&|WjrAAJL0PE&3tIA2D#<=liKCyTm8T=>IY1Qpfv4_{B7}xh@xo?xrl(0Y` z9nHa}4Ucy3L@&FBBw&`SAWP6Oo>U*G1j1)ZP?tMI;%EZKqK9lTgzMv^P;Bdww*K~8-Q(m#!65r%Jjz7l zI=&+rxaaBLB_{X-OhhRHtCRTEDqv5MG0vXl%$LDTl|!O>@o(M}Fa3`amYUF#hT7*(%`Y#Ym4)nO#{N>lQ81Pm?hs?P&y z9k0BWMNvr0ZH2a0scr^aW}8VdiPw?IQ<@JV=SyF>U_cEAI{a{j&lb7E6#Uii_7FXG zp#D^~#Tq0>>YSs=M9Dw*{N7&Ka3)(5iIm;J&C*Zq`VnEjL%Kln@;)AG{GT=&uN``W zi!Ya~GvHHa2hQlANnp_bA)&U}XFjf_ZCgXOvesz-1lF^cG+%j9<~;V;XrHv++HIxI zKiOWIcvJ1@PZ@s$M;o+;8op)`G7rq1k@3H|kck#b?I9Zg1-=Q#`cHqj zm%}1gmDty>p$&0|e$s=5zs)?eEz7}xhQdwaf2H@foMfXy0jVVqE|>1kcV5~sp(eQ4 zT(<3bzj#fYt$J|jq`xsU*$+mAvgO+DdZ^;oz_dkHi1GRzX(bsiOHsY>+mlD>IF{}v z?SQXihH6`mXQgsKoUelvpR@_Qk?cR;h`m?>Y_SfTq^Sx^Jj6LM8-MJ_|JO3Y9#U+kKb zceQaM8gGu)h|KVh)q0_yZhf?+Lat?Ew-K~4z?+LQ3I7gV4ELVrfiX`?tG}qKl#=(- z+054AOoRn`fyNehAE#`I5lhAW>gJV2p@+r9?xjSH2d=m(=aZeP zGf-tQpQ_WSR9L!?iP5GazB?rN@d7rpceA|Zn5vxRpZ}Fd)4)~2LXMUlofP{{C)raPk2w=VQsC5Xb z^T2<&(Rih>)$1ztl04M1yTv$_fR!2F8Prw0bSf9t$0+sWUjFSLSg|N1>!Xr8F zojYT)aj@fy+iRun{5B=ehwSBF#*t#SNyby2U+jyxK57wI`$$RqfNP0cmCg$QJQX}NZ;M{S;&lVCIaEb6_;RO9Je=DN zW6gFX_FG0An28gS-*pIn*u;G)=@qA6DSbk8;(ObO*1to8zMnWk3vY?b&qFjmPgLLG zarlzbtRne;RrhpHZ{g=Ze@HE_R{mJv7h%Sm0_6XkkHo{3b(SyYW*mD=qE+QT1PGi( z8)B`WQ<=G|`ifG#c^bpcy=VE-kR*X=_uhFT)C|m&v^}i}mY=pyRr3n?*IgsYj z6nlBqvy_&nn)=cgD{#nP+#Y4%fTF%_Wq<4-shzs>&aU$|*|d%6>k)$=}dq%m6!$^xCO9fSXb~q zKtc5q4{M6?yJSc6)GsFgN3h?@5@?RQt!@kN3OI8_K7C3aKH!FdIV>sy6$G8&bD0Q| zL)7Wy$|vrBXzg<1h_vK8IM7jqQ?#e}M;H!wXpBY=+B_1VO1Mz1lEazge#5o1OX81s zB2s0_wNA+WLcMyya99W5hX&hH?QXk<4gJ##MV^l-pi)uds_K$2>Xm<{vkvzPMpO5uKO({Xtoy@IA%JC&&L(~WvZ!nAr=%p9 zWKQ%Kz|JKhVSgYf>L>9cZXNdepKmPrpKf{b4=wXfb3|aXHt~@k__POq7yOT7e=Bj{ zOohQNUxeDemzj%6Za|NQpTpa zZ5i3w0squCO(g_q2^1cy&9&xEea*a=(5nTXul@>X!xJ6AgJndH?Hc6i!;Zhz>2i|V-)X$ z%B}s+x7dP-XwFC(9jn;Os9^l;Ku?3*ru(Yfp~!WFe}G-vfRhQU`6mkm;M1@gP}?$6JnWzURdSjX|M7YL4Jp}R% z#qSHogey}z!~-C50a#TpwRq^<*DgFPUB;h)`@}?~9xPQv>0Cslww0scxrdYX1uWvr}G$0;o~rZj<|zj1w)ieIzgG zFqMrN%?G$Ck>IA(K8dMJOd!GiO8)i84A6bc)%~@92L%QBOi2ZGF)nANrzY)tC~X+N zxLt?AT^59Y2(!~G0X&WPxQh$t_tqOP<9yho|8Z-av;qVfo9sGu%@rs5*CFnN`K}k$ zNI{5hI(7VeN3+0kmFi3=O}l<(e=ZdTY^(O-ju!ro=+bgzKv-L8_LkQ75DK=+jY1EC z%=WL%&cQ=Ei%yI*C)xlI`tt>f{;9wsC-uSscF(=oEr;$ zuRjW&ty^Q9eVT-nqHAU)FN>(>%+GshXqPu;vTf!W-m2iA+h`3$HDGruyD#Hi0sb4rAJa$duv!TF??NOdBnmgsbE{V~s$2f_&b z1*m9v;iy~xGabJoyt)5g$5AHPJ!0!S^4;NQ@Xsa3I<2N;w#{bgfAfzr2|!HghL>Hk z$g;Pj7o}xgU2lmL(I_G_m+Mabh&On~o zr$uW271vVn{A~gDp*>ULHDeOgqO}O+@`R&DCQzCQs!G~>5!g{yojKgiIEqNIj7sn) z2zT&N=b_mV)2dUBC|h1cZamStOzoQ#dMLoLH>~}S0Sxnm5ZH0l9n=w2{OA_^q|Nj^ zJM9J!QeJWg1a_5$+ovozNG!c)H9e29-r**-GiiqT7;~%EGh79N+jP-a10nC^(*c!{ z&e6YPr2gYMwa#}ga$+>ixf7nRe7&QiqaeE_@2S7|#Oc3{5%QgLz@ap)J_3QpU6z%?b#5f~13+;dY&k$Gd zTH!^d7=|O1+#a_>_8o5pgRU}SWmUT=j58XdCDHb0&fjWnAdhNq%e=d8yV1+9H}ra0 zJH<_VR9`6piUVa$zNiu z9>iNnJw@ASGrk3F0uU!~{{pU!fSit*a8Uu~m(&n;FyiRTKW>Y%+>K?i$~>m{j$D9S zH2M-=oPzsIQM8HxeIbxpF6rYds1kKi4FJCNYD&JGx{u?%|6atx0QouVE0&n&t47v5 z*}Dl-zRBydP3@M@Men+IlRROIwD*gZ>02Un^$A_S>TMxz!T-kxf^Prrdq&yFQ=sF@)k^_<<44A!eC38)kObbmFhs3 znn*3lxM{BbnYL*x6e=7bnT;po*hBfRxe?NbLCE$tWQuQtX5IYNtv`PY75D>)&5)b! zSDA8tPc!aF_w1_V!3G*M$0%NvqqtRMLIvTnErnk#NVzGlUM>&h{_u#cr3isj7qr zG%7l1$XLgMhAk`2|8hE$P{;iZxQQxhS2#6H=H;A|oHtjK7<_|IqQj#tzZ8#0EGx;E zNLO-g|2(e20m3_+*mPGqnQ!(aMqE|{I7UJEJ?9bJI_0H3L z828zQ!zFDirs$P-jdSecR;#qx&i$_lcVLIn^3QHDcbIG^=SK8Jc8tp>njEJ87!L%% z`+th8a=9Ht{1!X49&{Bq1~f(vMIdY0#%G>f-EJ9;qXbJ86~zo67&2!DfcALu`kyO< z7d@hhqMFARAtMLl1%bXe-eOMB45T|J9*s>&pt~~GA7T7Pfbddy^l6hHiZ0L7jkvs1 z6SubI=#MX4+oN;X?3)q(wL|7avi7-eFYCNPH|rVU)9ipFxz`{L!NG-{h0iboyuhHf z)7zA`H|W>yW~lymMcyGVv|#;n827^n?zO=?!6zeJmKhLT70?{ia+-5eg5H=E+1^q`W%k}`JOiqm`?9 zTxmn+CA`+6#8R&4f%yu=b4f3CU(xY3g=63|gpMSP*~+7EzkM3@*-K8g-Tu@~c&Uc! zs+|Kx0A!R5LbJ1|Itb5S1GQ5q(`O{-VZ?y3rZHw4{M$xQayd~09R$h-mjUE9k zx_uXFYHdT6jVK*UR^JkB58+=Nb+AVO)JDp&A_GK}0^Qbt-xwJZT5Y_jE?gDQXfM(Q zosFGbZd6`q$0c(DOR(ma0JJp54bA8X*kW)>(vhS7M{adA+{595>M3v}X8pHG3Z$QD zKj=>qx{s4;6(9fZ_|ib5fnwm+>XL(f&a^IKtVus1{>&i28%=R8*#j< z9tHQKBGNBf>b1>uF(9Ysc{%x+w|D+#3YyB>xsk|TGqW|~{g^O5M6$ggyG z5K^p6p}s8B4E}?m=b1>4ql;dOo2YQ%Sybpbj->MhqE8_>wQ5KRVmNr$0V0Aa3-CMA ze}w2!x7JwC2~irCSoJ7ytakHLuswVlX{yod7;c*elt}!+rtw0K?f)jwt&q7T?#-E8 z3~tRg3p98jL}qZdzNo_Jj3h5nQi6Q@5}Jyx`JV;OlbFL2{tNQ*R2u~M=AUk17BFaP zjQ2iMQH8Wr5pzKHmR@ac)u2`=BoCn(2EH$Q2L{=f#@nTvI*wZ;Ogp`$2VQDPeRFD* z$2(8|HSaviQ&^~jf+-V(Vl(eja!0Aq4t8rrmU>8=KT~CYkv;zfxPB26fAoG^X@ zl;53}*Ushhz>QXZ<{|On{K&3T*T>sux?ubTyi+74R z4qWqu+MigdH3t@92cNS{FQ{!7qgmNGp!gbrD!39HXtgTxAF-N>xvUp$JjU}w>TK(w zTsH)`gaFH9nk>ctGN8a+dqEGI1hEfqw~Rdyj-bYl@VZ0)$~KZiJI+JZ9Y=EQ$=->a zi&Syx|EAa;=lcCrYKD)Lk>pc#cA8GGXRhJ>Vjl^F-O)!C!VX%WVYMQ!Hm1!KO0zGz z*lX<)p(5;LY_W$@TMO=tPiO`CgK-A7rDEcR)JB4FS^&y;KO$n0d>7tLKwkK&;voMiW{GHgNh+UqxB(LZ*_-GN~YYYoP zHLGmP;sMa4IOhEqh!Xk|54ul;8+}uEOB4GYrB^U^q$KP)=6@;}tV_VoP&T2uuN5Q& z)C9va zD=&W1{&DhU%$r8;sVCXm3-CfCZ}%snWRQH*H~Xt?GX7ap2@h|Fcam%HgH^H=^$5$^ z3cUs$A^r)vh&VPSMtks+q3Ds-7&SY=cpIfklJo`avxp%OWH)1_5WoIN_Ir~ENpWI- zxB&Q+#<|?aTsZ&xIUTC6*L#gqL@kI_SnV)SUL$#}hN4U*Zlfb?3&^62W~TYY!S8Ad z<<83l1vIkl$^u|gS``J$-0M7TW%du6MF@4mSef=JDA7N2k9=tI#t_a(jAx!|cq+!1 z91y0P;qRX(H*BJhYLBQqDq`+2o3d}uOG(V~rW&X=3zGJ_+3{^yg5+y{5X1(UYqxvDHh?KOM7j^qs`ByaMAOE-(@ z)|y%Z!VgO>tr@&|bG*;B8$8>Iwt9IG;Lz0yO!aj>!A<2cG@PQws!@VU^5dO?{uz+; zZyYQKO*h$)-j0M=ET0a zQ}gGWVa$}WHq3{Fk|QX@n=RhuF|Ej!mu ze>Tnu{}16YF&Pi0`uJPBT8@Ml#cNPl^laN3h!<^~v0J(_gY1_dH|4F#=0Aq=rYG$v z`bD10kniL<8d9M9zCS|EcMV@)7d2EFznHc%*k`in(y@pO?-3OY4YB}P!y|^wo2U&< z>BLSYW8IpYe6}lL#Y~w*IgHZ1t64K{t^f369MiRwi9*p@3%kIx3o$l*M07Zcdj|KQ zNoLv6itc~au@3j{heZa2Y};Ojz?OW`$ebD9>s!t0Z-#eMkwqIY zv|-dKmZf{=xIf>&05N}Pyjvfo(fr$cW(LhSNTfhl{q&?|nJY7#IO)XD8g~{sR~(FS zTALlo&(rC;HD4re@4nv4I&<&*;#$;z6&EqAhsQCcON*I7`URRszwRLt-Fi!a0tn=V z$g|-4dHyYXXn0N`xikrI0^(Umu<2yd#8a}XMG+J=7i!ScbnyTY1&>5PpgtM*Z=ALm ze`uP|KPaip`=)rlHEmuPd`7d|cgwAa^p@^sr60i%Al2EsHTRxvA;a6%hfc)us(4`} zDccxMXV8+seK&uI>%NGwriPp`B)IG0E>PE7_T-#GmDL>Ul=AHb{uJ`umRaQNIdm3a z;DUUZstU$v~dr=xXl1P$_pU#A3)~&#>P`z>w(neuiAbo0)QZYCCc5h3BbpSh* z%&~%PPVTJ0`gAV!lHT~IiyV)Yx;Fj0kTp$}aQ6xFUTu9S^YWtl0C6di6p)^~yOXj| zMlpHU%cEB(1Z){rzWp(-N7I%ab$hm za~Dl2T2+BYf;f%#J~m?2(?Qzn?1tc>MT!Ova0lXfxT)O#KG*OaH0VG!x6~<=iXmm92teq`bRfe-RYcH##hh9B>l4+l*9*xOZ zpazO6`;bifoRHKSM$x+h%5IF?mYF+Bv2;kGzgvEn_=}nbMS&(>;s%$}I)`#8g_X9h z15ab}E4$aVo_%nDQXCu zq;s^K6;p1rwY?4nSFIE5^|PO~anZnnT2ifFp08Nfth4C85B#w(+rr>^PG zLW29@!cFPNWGlwiG8LiaO0vtcp>fZe`+bb2>^iGX%znYY3k&fd!mv|g97izYC63k7 zQ||n;GO@Won)h*7Ck>6*9{AiU$XWB8=6T|b6TU{8lpxy24c21Pp~Hg`;<8|X79}vY z_V8fxQks{X*UVY#sH{SQ2KFzVA#Kao&B&frptbQ;FUtZMB)Pr0Elss$$ZA=|ql3z0 ziZc|BKAT&7)fMX6Hf4A(Fi<+@dvQvOz{1T&Eb28&O&|$}+Em<0TivdYQAsoXEtS~_ z8D}wvO8z4=LM263Dqg|K7qoq(Q?4pMf37ae=(t1IpQ&oew@<0Dcn_cR@uS>-b4mcX`Spm9Yz~By@fqR3Yz?r8V4Uc?ZmhJ{KiTCgvBY_ul*= z+|CB^(iJr-F%s}c0>LsTn8}neP{Nb;x9SbcNY?y+w;C$9t~g2t`tMSNXcnz&Gi}MB z9g>xAsg?|m;MmplrAvMz)0Q}s0mh_-546bhEialFNmBnd*lRk4M`adY?OM7$mZI3+ za<_Q07SYrc;OGzWWY6#ZU_;rQpB3A*;pC!qYwfdU>~crnf3IaJ6Xkm}@6?fS)6LZ{ zE5C4forbdzHfh%g%W`n@^4rNf3d~Y$6_uP!fOi&HxfApG&YyH!0Zz{$p9n999m9-c z;#O*~BPoCUCrZ3jIiI|52nzDxHJgL3P7~p3hB-c$Dl3lF0Gba zZNCb@2-n{`d+`Pgb5u*{*$*w6W05K%N%7U^v3MgdGI?`eG?eD`$EdLjtoPfMrLX`W z)2SvE$&swZH7+W%$~O{K_rtG?>SW z{LbcxLdh*?@wm=r5OD(-q;*Lxf01es<@9H=fX)J>I4yy}eg+PS`?g(5q9RGov8O!y zout}ywhKo)=UBC%;ASN09~~3+H;cwPQND@4`o2fctbF58Kmz~6K7C{oCC7}EEPtQb z1#uecqL%@)Qve!dX*xJ7k=X%}@rj}EC?3%&14(_yb=OX*b-8IR^t8gLp}WbO0dilJ zrAQY`in({1U@ji&(n^rS@h?NjwrN6;i>nvLtMpW{>`A8VIwuHE2l#_^u@z7*BJ|6F zTC$Vt5I=PIm^uU<+GEx}LUDb64r<%dT4dgHk;djXni`WG(CMuAgt_V8w`{ywX1q<* zq~7LTZ7*UUXn-%Nc0Vc= z*x6-7$ZCz4Ab(WV9M02hSLZA*l;88oyBvPi(Z1XLIU3ZDyMich@myK#i&Bv&8D?U7 zY@m3`o$aF)&=H#uBCT6d+DAUFlN(>s+s6H1j9uL`IdI(&zEyXVf#8%Ipfi0rS+gt+ zd-4oWUog8;W2TstKTJh$5(>WyR5D5a*kEZd&YL+_V`0J zoUzc|@#C>U%)5RReMmq(WC%(+0NG5%KMd+_OPp*9)*=;ry11Gx{}8rnaP#ozHsuqz z&5d0S)a474W>Am9+|H?gPmZsrQGRzqb8+55?S7Hkl#uvt|g*bM*a zsC!}=d@5F_@+4>8j)bRbwzE~qqFtsba7p1;M{(xfqTOq0rD2$OyKa0xSNsen`HC!q zqR<*3{J0V9OPWk`*+@WQ%~>46EI)PFCt?G& z;Y4<@xVqPmZG7aG6uIB9Dt6PAoCWNAp+VeOKS% zbVe&4o1F8z(?73;siFB4b1C&pmy`nES%6@$2>)}H!U@WIK#v2?`&-HFZSAetWcxA`w_>BOq~jGkyMw658|~iy z;!g{K@oD!4sJ!z&3B)Tcd_`q+uiy5&Q18gT3iHvt=1@aG;|g^@(Lq-0S1yNuq0pUv zDyh~Qn5RjDkrMCH=c!K!*7A&r`UC@Y`aNxl;McSzK|b@nSVGxZnvv4#z_b;~@)a_sohtBZ3B@=?*vy~KNS7_^ z-DT)6V~4%Tk&MQ~7ZnE&xX&M{F-#I=2{!=QdKt)yo#K*~XSH1Grh2xoTZ^sf4u8{{ z#yU;Pkz@Gz9!S|wZr?Bi8(b5bIYP#iS(&=uG2=joD)|g#>`fGO5H@Si6F3p4Zzv4>DvVeW1 zwm$zi>1t$Ji_^o6p~0~JXQaYKX`n&S=YIbjW>L;?xb|PSyq$Sjw^>$B*)A_soH%Vb z8D3}?ot#D@oS~zQGhH&Omn*`}r80^`_G^xOe?sXyIBS2 z%`9SzG!vVj$c`E05{qEt6wMjB1+i541E}JYAI@u)IMi+ za6&Bkt*N=TXizVyiBoWJ{o19hJq4ZghOC2Zs;4uhVRq*HDMV_$UNo40n)uc%L3-P= zwpqe`J}&eoD`6YV#qXAe2JIi~s{_3=d8A^3#{BIdrvm~J#5)B6J^s1ryo!gAriFl5 zwkgZIMW456@jU9A*or^jbfQQcEn=Z0xQZ&n>%jvFt`dGS&T}7Lwd|-=Ow)=gF~_l?*hYe29H*25a{x6@2sjZ^@rMG z@J0--)jgz#7TUE@=jV*hJgPWrB}+`qcW-+nxMM8k8y*uDYwGB2i52=M=2V!Hk30A==1P4CgUVxKX=2=*{9Kw|nmc;#zB1KDO`e-!` zW1zDaLbVl*fmNK7WJ8{r2hH>V1H#gUK#kkJMe{@jbYz4h3ayntSWr77XITheADP;e zC3=LOZ#N1++*h5F+3(i0<>b6=tEHcTZ|l`hMCmsqc-fEbAM)+Mp)U}a<^61JPvF78 z`wV7?wq*h=w1>R&JdcCNTShJW#O)`wqwA_#EbVPtuoLfjuU~r9jg`of-_ujD3-Mgf z71}^i9156YM|wM}aBd!~-j^(6=tW{k)xS)JLM=wTW=m|KQ^$W6>QT@?38XIY~?8S3z zCux||(-(1l-TwG}6Z`;AY}uSruD_sbJ1axfb_Q?Vc~f=fMTIHFE73qYWjyDjlpt zyURQ3V(D4LeRb^u7oDM!Yh=meBYq_wbM zvX##XI{FYZ!bl3L8X7#y{UDbrW-RALhlLyWu@7VU0^cOIUC;tx*I&4s@Jcyp_uT2h7tuj@y%-s_Nyb;^zJVs?ioBy=RS5(QCh(f zh-G*k^vP%mGq>o!x&4zoK_=NKXa7?BPrNS3jmq@!`Q0ild%zgy{bRyU^IL;?i`Xgx zTC*9VUr^_ERY{#^4ziQp<2!Zp5IwmoNq+p6TXa=3lY}|rSy^iD=>!|WCzuxacWsI2 zM>MTRFwbuZ{0f8yZ7pDaA98s)+ZssTSEJuldSxQPo#;hrq{f zu1F&;2647uUWIAp-jt%``{i%VaV*01v98Yf2 zC4MRVBcuRPrC_F0$CVkn6gLCjguO#?Cn9XUSXhY1S6LK8-#9f z#G%@<>Mzz8v%Ihb>>kHYWL10L;+s_D8OzO#BRjj?H)j0w7nWr3zp;&lqTK-)@@MBf zqi>3`9^)Bx&Jy)`Lp3~|Z~r4|4g>F_{LHknSo^i!77?4>KFu~L`_GS2SmX&QXXyK` zc7efFhD8bOOX-rs$%ek;HE{i$BR&9Mp%ka%|RDf zf(THhLXGvo_|U)Y^-1N1_Ng+9iJeT~>QP+oh?CZ?NfDm{ZGt>5RW`sz_as4RJz16i zD?mm^?b!m1Km&oj0e^v(`cfnPIdyhN$j6zN#Q5p>fny%i_b2(`X;dj=7#xIWXD0I4 z2^5NBmnzs#pOzy$5V_SKluuD^jIn*1v3akx_L9Hwb-VgkV%QM5HT^Ey>PpxlOrzwK zl`cLeg@w>6S^JAa^|43+z?iLknF5oQ3EotxwN-A$+Qtj}c#{{(?v;TMVM$3z(T6g9 zjs=^pc|NX6Vbb|)Vt{0P-n_`yIS@E&ncvZ76vy4fl_gTWJQ%zFWUt&>)AQ>DYO=G* zlNB}P0kYoMwiqdbs2Yh2TF-eq6tuvti*B5B*LPBkWJChupQ^mO1K~rz529ZZo$%)t;HGgMfr*R2#rPA?#`tOo40%rA6x$Lu z6hGaR3pA0gW_Egohr39S@N6pmg*Rm8U-De-wo%3rQ9}FIrjYcXb;>D>$?<#sK~26b zj?^ZZ4l4U+{eaG>PT|oqr*3r9@q!5bb_WlqUj@9A#KhNkF!jI`4x*{~yh>_Zx*{113(&6G3Pv*dE;xJ`L9LdG2UyHd z4D%Ih@ADiKO-X^}%w!u8YS$MOO4E`8ei$UI+SE1kr6^G% zC>>TW2n^y7i7$Jha4}-J0d1LC^W8t>K0K|?>X0OK#lz%~QsxY3tXuTA$e%WAjdr%P z7dLY#ELd+uu&dt|H-x!7*g1>nr_B4KKI=CW0wR;)3Lcc{aIYBzmuu730}Esw^#f|l z05vb@D*0g=d7qs>s2c=R<9^rmdjp#Mf$jKXu@Ko$i`bKybcoJ)##kx%@>m9zA%O@r zlI>QWZ0!}L2B0w##;afD;DJ=GvO7{-UI^^fR*|Z2gnNE2IQ-@KTR@;RC!9jI5+ygl z{l+D;j10fRIx!)AS$q&w@Aq5Lr!vMZRV8F%emxFh%cuF9%-%DTCK)df{LZ>|(ogxl z060FP?u0CckD@(49znXB;m@Dto^7JHdMECC7FX~OZ8>!87It;atiq-OsPy{K?jFSA z*rW|*U-a<^>eZwY%8s)QDGwxG0f`VP1x+yLqL7jdhbeHUCL)= z5G?CBMw125o?my;@8K8&STQ0II-;9sSi#lJ-hDNxk5irrrQ7p57EPXwNcJS?VN9A? zf_A*Rz7p%{(O)SGN99%@u<+DGLcrq?bJjz{zp6V;8%lU-PP~ZwuCTk>RL14s(E2^I~lE?EI=CvYFV`f zMuL*o(JQvxsN3wux6T5Prq(wEZ_eP|_HLY(9o>SAa6`4Av{E@Cs=~BV$kyEIUUg9@ zU`I_M;vM`TFQqO9tiRs+HTHQ;l=w7UJAO*FiShQcs1d*U`Tuv|_ug8yd1t&;!|r%w zQ-J|O`W#wpn*^Y(FeHk*xBX6gVX}m;rg76b1S^3Xj_w&pTomZe|8dKvX(}VAQ~6rl zzd}p?xoskm-i-YfD6L~2ZYv?UATUOOKd9qliZYU&*B zp7V{1f)eYb_R%w01hV4%NQg9$#dsLCr#K_Uo98SP2;5#&xg1G=oI|}oct`KQ^&ccu zv8S*@vFF4_Tl9mcRH_Z~>04&_*OT8p%q!%n$dBbD6W`oN7KQnbpL3c=-hy%>%m(?j zZ}xgL#Jb-G8%cllNzA5yHz^MF7^QH~(tNOEJ|bO+gwn);wXqeaCpF5IgS(o^k8lC| z4J*ovYv@LIR)f})LvYW016=LA+VIN(5~P79g>$3B=wGP{5{CCtV8*{dyS`G(&B&y5 z(u<#QKf(d}gU2Q47_i>&a=O+!3;xI*^dJJAqshJ#;d6E@Vkb#dNnm_z zQL$%^Ruc&&Co_4H+abR6;*RplF|R(k-g_ zMMH7^1qR9Vx#D;lK}7xJ(8i#7TZp3WNRrb{;4ngbHW&{DxJR0@pe7}D6z^1klK}ND zvYd~<#J|~!lcz{0e`%cHzrZf#z*%F}NjS$$s#A9ABkS<>PUTNek9zlRPu3sJ2Q9Bd zErmXj$J@OI#08D2pI}k&bTiZ(puWH!5OKl+wJauM>}sQ-ZrIHTz1yd)+KE8NG*Zbm zdi6(w9B@tC&%WQR*+;>^)l`0_7Z-jptMx1H4FKA*tS4E=@X zOD|I5%HW#Yl`w?de2#$9C*gq_6eq(IIbCh6V0s@P(PL-q+m zwY)nuYhB-JiFY^GS1DaqUV5xeexfi!hVQP#4Qoz1`4eq7v@R1-A76{!92JZ|JQ1LG>2DRQuS&hwW@T*}%JcV=2 z2auhUbCjx<8y!G)@Q|bN3POfm&F`1vYR2&^u<#K;#6;<^aSi+H8R@>az1>cyrS=<^ zMR=b>yWE;qSm*^vPqi)nQ9!?EXP8=4#vbQ5f;;JNpq#c{euQd6~NPLzQXR%>8H844)^^SDRq3Ol+$EeF0pFLI< z0zSk2CLM$ccIPPB&b#{2*5)JO-)o7DV`>(;8jwmHBo^3Z{^ShB2 zw|PVnV9vL9pLZOB`4_SE*&~bT@JK`tjkD4O56fR@@2GvJt&rG28t&@lec>RXwAbUvt+#tX-{ng)5-~jUwWnf z4XZZr{5&cFM3W91$FRSglkT7S**avfpI`;V&+$diqzx;AfG(@4<-7fzZ_1oUc()(= zfnJS^ydqw4Lj{!F>kpf#E74s;l!)=W{C;PDnAPW*C7s|yx@}PpOr1_7bOzKq|<};Kw1_9`LI^@OpbB3NmvQljZGn;QkSISmPcL2Nwyc z>=(d3uzaOuzvWT1CtO;$ZTbuAS0!X!SW+DVhcL2V!Xe^U$XN}1`MX2ZAQYx!__yW+cxh+Z_jjTKFvBmSb1tej;D5NJO0;9ohF5SlT z>ZqFS^{vQ+f@H});pFt)0n4)xlj;ZP;ZcVRWT2&g<5KDbN8BM1ENhq+rvv|PIhqO+ zev;UJNzE9Ph-$8)zP8h}KS1hc&dU<>zomPwEDH-ni5Td0%A_M= z_QETEg8Gs?)R_UN4P@9@xaz$eWlUsICY)|XK33HEfqAbB>{1;3ydW(CpgK7%IX@afx6pl#=AeR)Thq~OrHSg zrDAIkA%cGG0{!}fSsB14ZRK6rgKhO;#BcQvp=@XTx6?6W#ZTxZ74jk?C=!F`4$PWo zPYrPY5R(YPjWh6f3P>9A)JplKw5&Aza{1vZnTYBMSd2hN@-JK{tjm4&-(Bt-TF~em!ga^U|5rqQ;(V%?|cD1Nkee1YkUCcY#FJf>HSU2JS>_cfJ}1 z=>xr$S*Yz{cZ+R@L!ht>s!2_KGeF}=O(r}I0_*IuCLHKtb6RHEF}QQi)F<{st@%5k?6D27nCS*3MSg|860se21T~e;R9dB z@M!u~V~e$)sT8u|=uw7(rusXe$tvD4s|wyM+9HAPq}0QB6es`En$3v8leyV@DGAS< z+0YX^p#8gtgA%lhYmS<0VDp1B*gIdJStldD=g0`GhjH}7?)OH@C_rl?Ej6)#lb<>r z$p@r*$!^olF4p+h=7OYFhy>t|UbMQkHpUYKTU}N@Xol;<2OY#phen(y;b1={qLZ4E z2;(m28z7ssGJ8R^81N55xGJ{^WarSjXf zFCMju6~(Bx_plptCnk%c*L&u+VbzF=7K+NhZtp1~8j%=JQDwIJaa7mMS#Wd|wX3O0 zHK@R2Cu_k-9M8%l`^=3}HRBuE4C_~g+z3#4XH#1GK()Hv zmj4C}(c=vwBK3uJ9^i^nZYrxYt36Dyr5kis~$NOH2DyzDSbK99B3pm_L zhn-9)%sUe9zky$BYDVGSs>61x?fqhB#~K);fxx$sZFCS_ty~5d+c2~79=|@B>7GV! z^^Hzz5kbG2y)K|>h4L0zpF?5K7duc_^FSM4fCa@ZVN}ZX9AR9} z0KUyQJ(j}62>0tpkq7&UYgstVQ0)$k*sUdNEz56!G7(;8Wj!cpDrj9Pf_ga>>l|f} zh89JD2vNb>YRiiLu)1d`)pdP`lBvbu_YXkdf>elc5$E^v`6|kx!CzE{uf;_^L4ezT z_MhMy2a1eF7~C7zI2Q?YynoGQnLg08$xZu2BEk+9WQnOM+**L%*N`=)3N9y^jOeE< za2K}o+4XbYI}g@bM_`1&Rwijv*DnNt4rj^e6y>^y)|eTsbgLihK3>(?M}3-r2u<;J@mtFckyB+#+ypUvN+48vS^tdYM%-=<*{ zGojsR52Qr)G;^~Z)9LF5pO1X-*$#kw{AYL_L(O6eLx!IPFF{cHdOmUi?~~w%g_3n} z%stzsw(pmTVAW;gH#CR%{7e{Is^3DK{ys|hL*dfAB9*odO`264`uoO!b{fwiHUZCh zNxU9DlMT&a&yJ~Mb1h%GoX*L~5_Y)Qar^i2KkGLZ&Sibx*n`=X^ui626iXLb_|~=F z>+>*gAkT{CetAal?*!)^ukInttDgdE54qhXvAU6KnO6(LM0M1cbYcFO6%@YPZx44X z_frg{<&AkO;5VF)G$~PN5rD+b`-&4Cnm_t0c+4MK%iId5vEG%01JIPJW}p*AWtRq( zP(YobF5EI)M_s*Ff1*vKw=1cYgLvq&bPdb9s|bx~IjT+N>|Y-Y#FRRs+|5N=vI zx+dG21HSxH+nYtS>K4nt_2V5=cTc$93^)XRxtWdo@$v2!nvG4(t{*9|#Mii{}^>RwU2dOJ~SyMzj}mr&t&LUWx)oGqH@qY_X}T&$^po zG?aG;nwr~VCZbWU>zTJM`HgSLd3!qA|Alq}twRB1Qn3fZ5^6dthNQrqI<);cYtp&C zQ>q`Lb3dJ!1)ABvtN`x2<})p+7L%w|C;bn=+YslaK2-n=_ZtyS-B5{`7fWyZ>SjDg ze3+`5qKhPHV*ZtnC#yFXK$vB*E|uZ4@_T>eigL{T3>ppud2-#64M(MOgk;1ZD_9$W z?R_#=*Cy=%oh%ONUauN{)}n@hKhM|~ubA`)$8Z#EZvAV9$$9Jh{B#P{Bn3$&vKDz@ zyb!W>@|r`)cb?ObH%|X<;Qk$9rNnq(?U#q`{szcoRQD`;!+=#Cp9Xm;+qP7dT-ZDq z^w#;ia|Tb3e;LZ-^ntEJ+hS@{N0a*SBJAur`dwx!n>MOda*MsyWe4a0){_FmY@^#f z1vsKmyLA+){RIw*aNuBs^2_;e=ajs{j3T!GpwfX!^rJ(opV@j(TA$>YAefst?`WCKL@5|sDL1kZBCVf-yXP{&{bK$Co-${T`yNvz?ZP0Y{#WO7ofH% z@b8>YC~A_M5&JN~$isxvWZR2TQvT^9rg`M$uL>Gh-Q2WrN3{KVzq`M@tGr2;bOt@ZxHF{Gu#rmbgH871IZxd=+yWe6*GLVrKHU-~VqFS83LC|p^bytkC z^BuNE+$#*--!8H2zP@tLYTZGY5rI(u{=fW=ZeS?sDvSbzo!jVTMl)DMA zY@6;AP6}_E;Ko7st-dXA+#oC-Ib^O|f6w@Vn_b@MyK+;DDb#kj0ykL6f1j9XCyBa) ze*JU^*gu~0W+Ph_@F@u*w7?uE0fRn?zR1M1_}BRkyqO4EpHpAt3rtu|L?Vp&R`brm zDt_r*F8zbyOc!~4&70U|DGK@|s@D=Id2|~&7&S8|(jCqU} zpXWbsyj#Y3V-S}hm(rMUsoqxl-c(B@S>&Rj)qZ>OWgz0&L)Xq}L&LSL^;vxpuWU@L zXRf7d14|LR#4I^d%ypZz+XO3woJRHRtf~zkpG~u>$dv%(G(WtO*B?fS(-4Z4rl>g# zzwqSoh42BXBtF$bh`lhQ{97XRf`whk)bH&=n0Z5m*5g=rq_hyTASbS4@!)U%;%U(erQYmoeU4vX1B3OSCQn!grGE^e`IdMe}0Sls}0cPwq9j=>Mu=5Bp0hQt*ks!!As; z$~`}%e)`@m4YC2YZeW?u+c%ic{{ph+1GjARNkiwh75R0F^7W-n=8e&lp00+VQvq7- z-reH`bxt+{+2^&{GyMF`bvYBj5ZEw_dNv%oI5Fl=fTo1~uGiPhgfb%+>x;Dp$yvr<_h65+J!4wMNE{K#)F zU?u-oSK7jN(m=Hbvs@>+G3zAsLmQ#uH^V$_vLNU& zTT1%P?Ay4nINn#@IM$Q&`;K7|Uyw25dM}NNT#PatHGH{#=1g2s+7?wcj5(5eJtZ_z z$~~*REXXJ1DSQValxF5G!VhIBA2A9IEXbUhy_?1Aoq>Fjg$;XhQ_bICg?4;=@J_k4Jgt*zT)Ip}22s>_&!Src6sozV`ns@^&m zcKpeHbK(^C792EEdS^t(a1t7$KkT=C^`*YCaQWa<)5-cUvu8ozZ@yv+AJ8d=cJ<`6 zkm1z^(7W&A@@uuCO%_*Z!vIDACx3nt)eK)2tZz$gb7ySU9lw710{P|Fw_ba!du|2C zqLihIf%8#)+W<9q{-P+-p?Bw5PA=ELK8@jTxhwwk3XXc6qMZas3~{?ncL{`43*o?Y z;c2#T}zcQlXs+G~GtM#uv(`E5nE!p5p&5x&z-VPk|0j_)yC| zTxw;5`}4bS(IGoh>&jJewj3Jxb~mD)S>2JM^{eLxKfSPq`GuUeF?c?Vfd1(=N2qQW zH%Dj^xZ4vk9!is{_B!T}8!?}C+RGPLq3a)PU~J6 zyDjxg50CAJ(ID!tUdzD2uTgyYuzH?f*{mmZK;JUERTu?|+XAHP*SVjtkOMSdtt~Xx z-#(3%8y_{r*^?(8C|Q%0zJ@j>eqmw7KkbpLx1^Dee0+T{lGVku&Rw!ebF9(eW35i= z9Q^oWL`QbwD(wEQh-={>%+YWl$!yQ0JFnN$M;uL>ZD(tudQbPd)w4eAIxizJ#v1n) zVPU%|0VGS6_*lqZ27LS7UIr%3PodzALAjMpg}FNKo68}TRgM9j+*(^gd&d`(osGYr z?)9r1Y&zL7g0qS0Y=%Z!JMjOGwI=%DK$gkyFIYb~TQ0W0mCfQFcE5OJ95CF0(=)GlXjEe7HRvFqpy7hg}z7+hroU;Wz`oT0l>r2gsYl(q{0G znv}MQ{(V@y4ow-{=u&TlFY*c}gkdWdgEYaVFES8$*QC%lI(+qDMY z+<_IDaq=9+URL2ZJ82sKdu&Y`zl9X(r#-O9;-#r5oH02b2_Y?W?dyx{jU%^gJ@Qmh z^wdTS_rn!RD7CSWpIPz^K~EiS3j1609&UF4(| z`}AFeBr-I63B78zkN{`Im5+TBm#M$7_a=}LlX|0K)gk0t^RT}bzFEQ@m2@%-z4tC? zSFk8ixiDTPPc*fx=(oDgCrOlE1JM%EhH(u)=}~LTS*4)J-R`J?EPj`;)?Dg4YgheEMzgeHfSd z5oB|x^Ih%|04Ua$Ll_QMooUp@@A%ff)|Jc+xR?85GuX4XX2Ebjr61B0MSWV{B>Sr zNQO6~s;jF@g^M@p3*!>?9+QH~FU4GepkM!WR~#1JzV$Y9}cPVjH9&M2w&W?%|V+|60>b zY>CzgLfIP6P+h6Koebs#zw@P@Xa)jMhu59gBh-9{x1n}nywh9s`33`k8e^S4Z!|W= zG?&LIBQ_ z!o{fMkKYSYOpm4xep(vxOtIw~vKvqIy?T-lUXzT)I2nT8&8A?I=oF%u}lu&X}@QyEFxMhK@m;O8QA0QsmT!|&t zEO#ph(kxCstHzvAJ976qYa2~?9R*>pF!3d_`sBDQ%R;YwIh*hDb?35u03ugwIvOH+Jm%8Jxy6^dS9V}*EiCk?wx6CXHO(oQ zp9Db6VjLD2Z{>aG*hCZThlfN4{!rD!?1PaxLE$|2z0s(vChzZB?MYoZ^&60k!VC9p`z`Qw{eXzEMwSI&qZB_2?^niE0jXB)f0ql+vRD_zVG|f_jKw;GaK-23^@=5Wa8vJUu{w)y#WD-|)6g zvg1@#T>_D9E(RZK&x}wf&L5qk;)M2%JZk`x^px4U4uPpNmM}=s8tRy2tHd`wrcZ?Z z@{3$bCdzcF{ze^mDm?YeZwcAu5bA@1KyINnrv5TPZ8&U&1ggM@)T*W=JniSc(^1Vu zFqFjyJVgS7Ov5=C`Lob&3|c#=U4^EY22Uk2C_6Bv^iE6I#%nrY6+7bY8%>~B2@%T-D%n( z&WILbx=U>nZ?XvZuVoBK0JqBmv(tHWw;O8M&9%F_(hw&vT)=ddd8eH2NQd|L+Uvx# zJjX=xQ{*&_U4&_h?ndOj1-$7Nicr1Socsi@Rj zjJy6b8kH4=!-159fMOn5Oosw^Oo?)oZvDVF)fWmCxBsU}z>&hIPe+5h5mlygIq&#- zpGcE_mRwHAI-430!Q7#B)0O$oUEY~+RM_B74f1m=bI4Eq1eWoe`ma!l=9u!bjbUX; zfqzr_`IL^ z7k@ZZ)mb5zY2C8LZ2l4U4B9UV*Tb)6>!=jzq}3Omt89Gd2{#>ToL4;v^!li^KD^}A zLSD!@;I(=uxxmY5PW9#x3Q7&Y?#lNUlZOGyGXA9hMoa>ie#cm0e{SmPu+hMwgAtIm z*jiqxO39P6ryU9yD9K#HYGuLM1p;0((1}|BDYc{yzNJ=yo*@k87r`{E)njXiyBY-t z0uMu`=;OkTesyQQSq>q8UIi+D_kS=oY9#C*y*V7zHLPcsoUKJ2hgXg3@%f1@9{KC# z9LiPst%UO_=l2a*b|3jomQP-$qc2YO>9iVDCzN2iykbT&ztR5A(TZ7vbyB7fN6v>% z68gqu&thJM1p)A`zOtzA0QFKYiG2~)`)y*qd%0zrfbNU4%g)#=DzC5W>W9jYBFS!B z0RT^%&SJL(I%l|7@~|ZpLeXHB+Y<+=D2@1B>-od`-pyo%5gcNnw4RS}R2^OTKmLBM zP3O(ov^!*Hk*<4r=JKS6_r|oEcl?`#pQ~C1=vz}ET2>0rnyF3>>Ylp3sL@?j!&XUT z6U#zhV1NqIgQstA!fXOTfgcadl)tT~(2!*8>y4OFyC*J;7!7bKJCX>l9l4T~3U0_e zW1{{MUJq1q43wJ8lJ*SQPTY^7r_RunM?_CNOMyIxW1}!5cmZt+Iv~cmN9PH~F??Ur zIWGFW2Y`*oDK1i~{)qpqa!kd`OL z*)+Y&=2d6-M_s&dKeSqxyXGgb^_rMLiSg&iZEtaTPhUc9qj28y=(2fCAUc z{5jWcHw-U;yA*@mydVkyu;}0=!05u+KI8T=;;Jqv(?NW-2=hKI4QGS3a8E2~r^xv| zkh$77A>a(nAfZ+g%~NSw)~BSB02k2Us&SHW9{CXC8#F=zG@Nt_&a!{}PH*%+%i(7@ zxUNs@3rxn9tJbLo8KSEoNi?s-9^W4lHi)x{z>o5>r5-IdZV}9 zU4a|uBY4Tez7Nvb+13VJp3hZjY3tCZWoV8l5x{f7d^U-H1q4QAPi==~pY>miBm2V^GIXm-FA3!{JZw8(@2AXAanaQiT9wOEJ+lylKxNGQZLw%b+S}O z((^-;px(pK&F-7sc6?q3+C(&@dDKKkVKZ z+(nB6q+_SS>1=8qk}a^>M!??2XFCG7ImEgg@5JTjeer#*<(FS=JNx!lzfo~L7#uk+ zDDf4xk$adRzck@Basj*P>H_pBAK_bSBu#YJFnT;Kc%nU>4V1k2>2ww>>4t#g+q7xe zFb}?i=p(@4U!_ri9HI_PNE)ft0$BmrYEJy_(va?tH(26$}K^KRmD zd6hp7DQ-}=p062&T#8@+TeK1GbCHrmDH22*^i}@2q@!B5Y#u&j%>>>}JU@yQxMfp} z?k*6AZBQV=EcPT~Wso4wKVX3`F;|kyAt5(IIUo>8R zNMMQrmB_PjU z$@`f^fx;sWSs~l~!xK<2mh|e)en?Lh zJ^y#-0mJaflC4xzpwsU3#V|ke7)pPOjef=tkhO)1N3Gmw4#NIJ`Qnu{Dy8>E(Ao!QcjHDJ07l5Q+pwTkZN+d8Am)mwd3W$5h6hY70Bcx0vDp4WWW z^M{$A^1x&S3CEDZS884m>nh3OPYfni3Et|=VA?})r}9kmi00odv%&7vOa6`k9 z;{xHd97cE|-6j(COF*W1tzLTPqK;Fd;b1i`e%tg?1go0Oq}3GIs3?6y=8xi2G+RBM zC$4epA~lc*Z%2=9FJr)rq(p1l2iZqW7UABQzu1gW1$|OA=Z3C+;v=G0?P70MLC&A& ztR}9^;zXkSk(8sbZf`+;Z8TqxtpEU-b7N&&&g1{dZxu zig|{1{dA7mZ!v_?5`~l34ZM;e4k^>4(HE3SVcd$polw78s>sq{KPjV7B?twfF>GNk zs(!8*Hi%>1;T}!cv-Z9@jsxq}v)17;XH!5pVan`FvD}~j;hOYpSEU+MuDXL49jolg zirA#c;+oaIh;4hxxVq=l3egYHZ-;(w(;^qDz`GgovUx?Hk!F+r^XtQ(5*NC8jXArs zw{{5v1mDDkOwVgLZs&`2wAD_Y$Fw*S&DM7)F#|Wn+YFE$gA*3;Xm_>-c;97q3=Sp5f!n%fpHY7P1IQIoF2Io~CsbH|AMm&o1{* zJ-Hel&dfsYFPp7UV{QLS>5qFg$}Es9+Vq7sD-_e0hIa7X1SXb_A)Z#oGzI|N zn+xJgd_^nUR~nHl3(E!6nEl)Tqw#jeRB)ahRu9gIc3XhCMWzCM0(@SCl60iKgNUB+ zt*r10vM>3*eco=5iOZ6n@K(bH;nM4r2s8R*UmxO9#1?cig2lK&(SNUE@Ka5BOhVE@ z2=kz8xwc^Au@nm}I&(3R4>kRC<}yBU3VroHvOXa)2IbPpYi2`poUJ3~-X{t`8I6=N zz#B*Zk4#dyVF%UT0jquLBQp}R&(MWRwKfwW!tj)bxF3xfaCf4?zQ_fY7KEhc0)aO!AM z!}^1i5O2?Lg|EH#kln|>+J%_Bjdwa4QR{5353fp#tRvA$E0iXyR?|b+IvkdC`6y-l z|25ao09RH1m*7&+(fb>Md^-@*6Y1Xe^@6{Hwfd}rcgLc^YxJvVX>(RW){OhxbivHa~GhLIc?U**L7Jlq9i&t4@8*me9p?2s3OhdOQ zKdYV*wCA_m&)60i3|VU8T00)=H_5M!(CBl@CsGR>hfz$M`^Wp3FO2#vDz0KpUR84q z{$8r`H>^b#8JpP2#|G%KJ(ba!{ZW!T@MeI)m$&qjiJ0TU&%{{jKkR(#D?$s2YCL7Z zNuXGN1#7NyS`t*_9Go3&fb-1UmiDxZ)UlZI_w{SpzCY&Q_zxfwZ!aT=f#hr-S@?*E z0@YF|udHsps^6D2L3a;LO)_wQFU;~P!jeVjy7?9P}RcU&Fn|a~2?$TU-#_R56x@Up$1 z?*)uF1C>Pvy_aycPmf%(23->5p8*uL+zod~iro!biIcH7HW8{JO+q<#MMKord+|ZP zdZKWq@bQX80p!?q6`=Ie7Ai^#9cX|?giQ5fI4^|T}F#x!T*jWpnS=K0dR`qXh(fq#<#9mK(8Ogf zTz*=s5BB+qD=PgTGKeYJfzFdG)?iJl$^m)wOG)q@Co9z_u`ts>1jD{4UZO7$MU(=?5^ zFn|BW*1WRvR{$XgGkB-A=}wQZxClc<^F3*fWzLd}IwY|5+G$~cE2kaKM^d%*oHdNVKO zWBdp}-Un0-qh(N@}EoVu*j zz+!KgA5;F5(eyp7Cj%oYmKF21a}O($fQ9d@&sN~O7=9Ef{tIHbB!WX=L2B0BC84VL zc}%5=VS=`$i2T;Xxl6|8IFD-)PQO~rF(BCn^*O9VAZ$PQ+s1u)20Is&QD58_EUsk1 zLn+Y?iEB-d1NC!_9?qE6esV+l{r1LEVh%!3w0RkJA6lml1Xpa>|6mEg10dMD_}xKe z=X!)oV5>F3;O>7SGhcFBq|CuDSALhKe-i7L&9b3@y znSSh&5GFPAs=cPnW&jCF&~XO6ap?CsZt10-nZQcVB+|0x%}lfaIiRr-euRmOsf`76 z6Lcw(OOlm~{Q~6lXO&rf$#nE*fGR^`rc?dKpSR}#uONZ?*axKIZ_XK28rt4Y@{i6S zlx^D_sFaohiUC-mWt8?!V0yzNVHX{%Kp!xyIuo5{Fb2LJ|F2Ew5B?6w==@b72aT?rPoFP_YcENs1`2S4vO$?>>&fyH4A2n>-7J@iblwiu^( za_E;W2g)W1Sufir=XSZBws{@gQ$Mc`!sGnuN@1&_D2~~`bFL@@jpDH#NIgG{=3Bx0 ztoG$=z`aOe`2ZEvP6g%iN05k)nk)}5%s^5W+RSfxN=zhZzUJWCpfL54Sh5lHQO&PH z5Kx*0xUsdOw?d#j?$&Gb4}0%Lh4vS{3>QHi21!po5yz?-(bl=9V?XtYMON*IwZH)) zZSBr1D{wxjcCC^Zr_(nv&msa`i}*UeO(H$nuS?(U9RX#;5U3?AI-fuyP*AM`Yn7 z#@f@2R~zrjv!P{J(C36E(>j1AC#5rfw0IRI_7$_Q#AapA-YxL2o&OKrY0LjQ40tOc zx_SV~9NKg2(lYV|w(b!-+03l&G3~dRn#t9C`Q+p1fZLujzKc(1tUBW6qCIN}zKzz( zr-*9Kw6a|@8@gx}nnZa}6Wvff)oFBWbEzj(dk7CFX?6*2m(98TP3rAG}&7z{GVQTLw>PP+I}a|rd9kA(6~TtU%-P|za@K!Aslvdk6EV}_5#-SK9tzJ&2#;a zpC?&q^P0@F3)Vi(H>wzm&=7&jJ`JPImVneUV*ovMAZt?|(uOW1gaQSKAEfk>;EQg{ z-KDK)0;yvb4!-lc(;Qs;yqh_s-L@Dewmc+g? zxmty@`{|b4GKP!HN%yn`+xkexE4}LZsZUSmBDSD)bm_F2n)I(g6YRLpX} zAp@h?5A@rG-0}qShL4Xhvi`kcMcpT`gbaqV11F--fdi8Etw}~Rc-+wSJtgGw)kVfv z!bw%E)5>`oi`n1PdwC}D68V`R+izmkrI{ZyGbhU~%saLAU_Isq+*RD*cPvq(p%=DV z{>Dh|gi_No_b*j!6!1_RRm>BC{il3NAxew=QpTc@&^V)Aev(9=x*Mi;3KBy7tCv~I z>PBRllT3L_tenq3RYu0K_hms!egQuQMTl%pzMy=-K?dWj%!W}k0?-9W9$r-EFtvPLm*=zEDfm5TsKYUY$4l3C53=F=cF~c5< z??-uPGdI0MA^(2I;s2CIMVt{YUTEL3`rtMnDU=Y?Vlm7Upc_&vi9cu~UdWXq*5zA7 z7)OpY0Ez%vX*|*a{YKdHmtd;Mlx8YK!zEonN5V*ITYm1#&yW)U6G!RLBWof)$ik|> z5dzLTGm6bWC{_87P$4V@DAsVdBzi6Sz0By zS*Ej#(R3vH3xSo}7%5X`O+j@x_Km&iKSlzMJm)d-c@+Jo74y73=H&zh`JYQb)I@~C znJz)QD{V;?Zl0V2;l#SpUhO1zeg_9)Z1x#$&vAk_I&&Cc z5SUZU5T~ph@&^|@RskEB1Uf&|NUs|cznKBO3;$W2Y^)Sge#H?7)GmjGPDz=T*UhW* zFvLD96Y-riCd0+J!mG+-$aSGMS2&9T{%0?*YfRUJOR4~qeUHtNA0%3c?~pjX{_C_H zME?Jw=a)u@0d7A}rE7qq>}iw5>3ZqB0EUi%Ms#!tG|{hAEQl+mN8efT21^PDL`C8) z;Iy?lQ0jq#miVGYi3{=3&$*n0jB2Lm&Wf|v5T8VCK}rPT6wBo&kB%p>?un*vpAzJ5 z?mb|hbST{KySOhw8)f_+xAjzqjOq^>ZC!*{p9vPS%hkLIj;$tr)3h-lSGM$jxw44; zp^H}dm>S9i1e`?k_O~83zwCPI2VD;HTA5DMhcI`2o1sHYwPOX=d!-?UKF;WL4=|v; z@>Wx~ABt|aZz05IDM1pzN~a1nX8Zh8=9d_T36M{e+_qonVH=?ua9ozK884Ixz{_cI zvHe>Q-0tEcwRq0)fjVlX2v#zdWhG(*q&O#9;4cYr;ux7>#N3=rlF zx8Gm&>pUFT-G!J$Y_hGT5bXg{Z=^e7S*KyiL` z)s)<{;m#&V6?{+!Ea2`yG5yQ%;M2MqE#$}@9d_=wO z6OwP-_mrGYiQbNqy$C0SmRWzD8_NCY8IOs0 zP3~NO@IkTVJ%BdLGs?e4TsDz`w>qtlkFP2Wof#sc!T`pg9KRSx5qEL;y?T%MM{T0;x3>184T%II9 zj?LVb@5OPy)QNmn-o}(YlbrvUm19kNBn|FX5pU?HTwlm-SHG@Yb$ylK9^rK|$d09F zh&ya`$*96NoeTVsVpye`o%vt+ouE9O|IAX*zh*_U=Fvn(N;*Gc<~%}Ar2pvL&Caml zv-De+mqORlq>Bv-o%X zns!LcUMPvGQ`QLnA@~1>3eM)=1X5NH53qh$yLBX1*CV`o5GAVwYXjnDy%_?i8=$_* zccC#jfo}81Vyw4evuER#=TA;?XzV>*yEg9R(3%Zm+eqa{|!?*_$GrtIjNT~lUzFAU_|W7KqU zu!_cO)-|J5ajb3W2#uqd&sR`aS{nF(S+KG#JcxU{S_+$u5qxR-IF}C`GoeNitLkC7 zDT(XfS9jo?+wptVCH_P7vOBub0iuS3T+fCU#npj>4z|{5+Qe}|xJK{5JTkfLj=W{o z;p3u^tBX#B;of?|S=D^`7*D%^AVOFc-D>p#Qzj2nh76-5H@S9|)xaCP!%T*k%~E8G z-83B3fD&F4&o}m$@WwF>(?}I0S1mn$OCBLa5h%dU9#J!oWr)9HSLck_C4Z~-wopLZ z0ri|MqE~1GM9MhoCyS#Ti|kT|iX=fv8vdex4F$gAtg>c(B4Xx)-*OadgPPm3M*8=3 zyWZYVl!wabSXL(ps?52cj)N@9@v@oVNieM%e)FTMwi*98v&;#2f~F9#~>{jfis>CuNrP3HAWqrC#;9{bdCCuD2(cqC2uKme5IaSRdz)gJyk$1uh#G+$_=k0PW%+ zkugUky!3}cD5b(!MgMVUQf#;VyOyZRK zDH`s$`jLzOv*jVDX;B%k;u0eXg58e!Q6z@He1ah3QGy&R7jS zd|11rZ#jbZJ$4yvSz0aWQ&UCr6d5U05PhO#kC?CzQldK|hyxA5?2WBv*`{1?x$Bb&gT4G{zN_!%=~Y=X*SPPE zZ%=Eljk48@bywinSks*NuiGC*%q@#^Vv&PBf5;v3RoM~F%2KUP^p}Wlv+$JM14f3q zq3#%8GxkrBb7T;Kb2KchJ*W;K|rgwq*=CT`dkD zko|$cx5k166c6SUA<;ZaMMbx!{9Lx1;pYW;Lz}^3>_?VaIp6?tX%tow`$|JZe&6uA zUR;0_j@qFJ=u|mEr$;1AfI%u|08_WgOnX`YTgZ3%;8|P95QqK>Kt{SVuSA-qRQ*2h zlFJp#JH873zCeeTkS|03G7#S!7&x3PHQFl`8~sk}@BIDWhBit&`I*}XfAX?yr-s#u z5(CK?GS|A@DG8cJL|j|ZYJ;dHFz$KA)q1qJTd+M?U||X)fM!}}eb@qD@uDkx z|MPC_T*3iHHO=0fx^maFFarj~dv*3H8369GFgfBOo|i_AB4&c*U;{6VNTHLJ%Y^V z26zKiw_Ryq9OXBwpmz1f_1d4Z?|SJg!j16l_7bO2j^f3}Tlemg{XDwU7zOB7z5h~* z!P zSa({)zq+RG=AQTM!Eka9KC$I#7WuOOvZMb9U=B>MnN~)_1saiJ3>F_uh7BOxGS_<# zE{lNjoTIijdP^fn?GypQ(576sQxC()`74!O_JVjIG!lGk;-Mvh7{rVPVh%O$vTI?! z^di;v1ONzInP;PyTK^rHy4NS?k2~^LDwB!HM%c5nW!}u)YQ0WMV(*X7587N%l zQ~>II2@xk)mv=9;=1lx9t=zNeZ4yL>ZQYsV@v{%nC)7Jj0zL=Sh!0d^LvAo0MEmQ_yqV+ zxU>z`x;fGK_rG70qF7F?rgbN=)!#iN8fMtRQGxWd6w!P=+@|1Z3uA^}Qs!X;Xh6RL zs>wG6r!ck+7dnjl7R{rzzpO#(?x!X(r;VErq02g*^LaL!m64Ok-%7BB<;pV(SPs%4 z>drFoqc#xGDaSulFOtsUd_>P|qR1KDs_QLbBs z{*`6l#~+C4{1ex}X+@XPVO$sQhfe44huB8vFKnSq7At%mfGSViB_+EI%@H1?j0U<- zW2SWFCXew4O~o-6+T=Q1B7>;s=#82gG6APxA`GqDX6HZl{(Wm2uxi-UyZ zNI;f8M$Am%mL8<^K&8%VrQ3!8_iOTyY%=4YlI_WDzgqHNom(ZXQ#^k?1Acwuy9|1f zx+p4z&+lK1VNjRh@rb(ff$Cl8d+(569++x-GA!brZZgDhquN`58^SRMopbRY+ zu%cW;3H+D1pCj^BH{<+4Kl@=$Q*qK{0cU~+zv)UCEPoz@KY z=G$F&-f+BrFnZ6es0Gq$lM%O9m#aTGmLi;$T(9A71uhPFfA+NV`Ee4q<`t!_p`~l& zw2zWbCWJWg*^+E|st3SK3g8h*JZMhR_tsj%HAsGQy7Zd>)@)a2|UEj!DODx;_M z?B9IPe{I&{+2btSb}$xs!R`HZ+(Hyg1ih%%4KoyEPI5xas4&N}J~Yqv@N&^8DZT z*YdJm%PpJB=CbX2vTbwOEiOFS)^f|Xt>wl2?%to@_c;2uI#hW8n=n@zBUbPDi!#_DKz7^e?K z=Vf|~Zi{kgHJe!oeA)!Ohq7;kx=OYhMtak900m7t!N>Yff9(AC3`wZMC5Sc4EYkTW z(qWgp4e=D^OLsHYWMhDzr(;c#($@#39x%0qdevm{b<_*o^lg9MK>~Z+c^?^l6WE50 z_d~J1k+C??*8oGM5!b(l#p`B9W!{*uznsF5Wz3wYF&EI{=AqCj!ciOleRT7yT;lPE z6{}&eagHM(YS12TOmpejmdl_^aFg_?%Vk@aFu%Pc#6;Jr7Lw@ zK)h+v-V!!4O1Lfw4HcHVZ-&#+9LCOX0-UvbwEfUL&{a5g3MQ)r@0ACUa3HLtA{B=C zz=xr1gIe@Qy_$nhF%~@X=2p3jDD|x&hJYl?w1&t1fWTE~rU_Rb>97S>P3rfW-#cV) zuf45KquMwrAJTHW|I{wqqxMCuXDeJQkwjO8v3}LeO>mR@kTZfgV(kNrPUqgF%DgPl z89z@P7%sLl#`i#{P&g~qB|K&BhHM_+y zIW(-S+o4=-3(i^`KB&Frg@ymq-Op-umWVeFK>z1!7KiTZu3BZZn%_Ug6&MMm0(z;A^{1*(&7l{S)xAR)(ft29LumQZr%^V}4>+X@kPW$yYi{zFr z=is~lthvze%`ye&NFojX>CEh>f)(elrUFCMIn)}R*58HQR| z8$G0{LL2j-H%;)lpC*%xL=7_DEXWd);P<4}FPP}}DHWh#I{%Rd>E%5gea-Z*QwwcS=^4K5>Z3}e(o zUniD2qzw_)%V}|S+u0K@jEqChk3s)MuB>8Qas@1<)25Z*vH-o86SEVTnSy8htMHnr zOZzo-+Ni`c)HW^hC6oWe0kHP^jH_G!$Ya%vd3Pb_0xsm94U*+uiW0uA!mk*~)UroS z7NK!N`s`G>_G&N#--f{-ltdm20EOoTFgUmga@W~K-Lma z=T*c9Bckf7ap*fHxD|Q6=rpCX zNhJ5TuEe+;RkJTYc4)5)Sj2kdyKWmjViRrm9yVjVPrUK1?bO32g$^onPS`_`XQ;)a z-r5&OGCYbMMZ)`Jh#Q9-V1zVBJ+{+S;C(-2S2_ZNsLN&93zh_Y24@mOX_1qN;P>?0 zfQ-La5#&xRg>L}+o2lkV)+L`2K_X6!xUg`C>+zw?$yiP@)QPiNuQ~^XJHQ-&5AsP< z0;;e~9~Pc&{<_k`s>y_=&eRVX9uVZI+skyhM11~>>tpK=*A2$s210^aHnYCi<2~L9 zK`!OWUOKmpUN%mz0Txh(Wy_n_=cFa=j56-s}xlFU`=wRSn7k0+4CynwQ26pco;F}{pE?p zGw;mkPhyCqd2zRZk=0_H|9(goJBhHV`D4)kS>p~uuR>|Q|0OSEzInPDRg1E{CF=o@# zv8CXSL#{>jyHww!y;-v*BqFm3B~XP!1ID?aW+NV6U#>5I_vr68qad|#y+FZekki?S zZuwu}zc{8)1UBv3I~&|e9~J#UC|!9RuZvq3Vdbv7ikQaaF8{J& zKH>Adl&c?wKsgM!yK)9|tatc5`gU#n^$WYTyrkV+qJGeOtCv93P=LmOCO3tA-g++C zD4E{3q)`?!H$39FAL3@G_*?r=%w8~I;@tO9mMQ|>meS1mUzAD*m*NP33)xkOV=;4l z<$3)273CgvQW-Ti=70IL`ds+UYxQo zR@+`~itGP2;|A+?jZu51dDc$6%@hb!R!`0iYdpRwFmEDl&Mq@lSj9d*!R@NcpCOMv zhD%k!NH|CJvr>e4=%e&`QD7Hff5-KPx3{XMcvE*6q{IE~;DBW-$3F z_L+}9WYsP=>&B1Y%XS;pbF9uRqi9}t&NL|%+csLXQNAH~#-ZHF=eA63I)iw21>X|k zMUC{4t<|d8!(fE z#;}RCYThE8@f%PGg~Y+#G%}QC-9aKP29!acU=Zc#x7$ym&!`M|Ys#jW!+LoHdxr1G zCoB=(q~nx5zq$QEdF+zE3*E%|u!r5P_ri6WW>w8H2NrL9fmU3nwO5u0QRpl%%)p2zcNfPrEfT*>JEF$=cHS`ECJlBjZ&6}k7Sdj6k5q(V8)-T!?Be18 z%_PM5F;m#FdsE+%g(#nq;VCT4z+M@f0u{?jYb?jUw_POzPy4YN)eyg+;T7S6!2?(i z>WwWsF$)l%7geLAil*m`Rt6CB${IC$69hl)-O`2mv3$0xoban|IP1(AU%ngh9?i|I zd&0r`5eAP~<+UPziA!fn!)F34G16a4eJr>S2e@ZJ!JZ4U#`^aByaMC1#kHn5RGu2g zWUq9#BHc0a9PKBRzrSBC8drtJc(+`^;Fb6oSb)z91f6jgr&M=OtWvS$ETYReev>cK z;KTOfK5D0j7ank6|4D?GC>`xk=gjTz^Z4YvlJ|3fRtab_U!8QIs3|TjQW~)m5yqlZ zXI-7WJCDg2-#6DLnSWFw{IzAn5L(ToDQhG#R%!=M_rpB7Ac5Rpx~onJ? zFkUF%wLe?=ac)nDx@~*ngA8x4D6!V*3wf|MqM!+Uw)8kC>@zQ6gLGsYx3TY4IDVbG zHtqKeOzE#j3s|LEg&3O6H&6l>slM(|oZvwk|DD>BLx1hVkF43a@zREdW=5&(c5>~A zOc{pgVJo>E!LA0s-XC5R+nk$Af46R7W$$K{%wpj$)sHR@u4Dd(+P#Od+a|xIabWLE zI5;|}r&juriIp*GKn*)O+%UoMn zY`Ki~as-`ByXAG*s{Pf=YJ8O#?!~>$xMb*Pc~$qaJws;aZ6f1p4&9~d}Ox4yWH zQE_syQctSc%G*5Ts(G-0Q0ibql;gG0d}Cj1Kl}N+tVcp_Egk-V<5apJo<3_Ycb}x@ zw`esW^}x&NQte+&?v`3)whT!4z_o+6ijy_Y$ib};(Lk|%UP%N!Cr(?;VHIVII5f;! z`B6fOxO+a_UU*LLBiCNx2N;cF_An6NX%rQY!ah+Bna%3*nVaM4ONqkXSjoe9x@wG; zPdQeb%i6f%w0pB28}N4&KIr$E)1+FcyWhUoYDk||7)`z*L#Yzl{S;rl6~Nu3{BF~5 zW0ACo!g{C;3#IDL1yO7HMEsvxNk6U2pRz!?H%H-F2eNYwt@~z{he2Aph^5o9=It&8B(XW@3gQo&vf&g!8KL~ z{ZN9r+|a}@KyhW{&{({KUEZXcJQR{ZhJ&Vd9tjFIRc*))tS|73!|2w_XZxX@JP zScLuKW$J%rsc3`~7(1)@!y`n!a&&<}!n_uwX(f7;z>F7C-4$)RNA2L+eKxvlzy!_~ zxq}+EdmS_^r6C72-elUh-6QzOIPk`raYL2Z^cD};UWw`5M?`Np&kf zT!<$q7&OpS8NH}C3P~bOxk0QEbe(v=H2J-#{|@3zxhUW5Mi%e0@zHX@}oA%!|LC+Ejk8sULI-1aYX-v$Pq~{CZyeYG8W$^y24-u8gaoua-nJ zbujm0@zzwXHYYFGntbP;FRJ{)kLQH0Q@?<=zP%$&XTsu!lE3M1l5GscRVnzHdA%Dz%h zPj~U0!ZZKur}!w+41Op$lqo!?#)RH9#yWG+=b;I{0x z{4d?Q{TGu{SH~pwtcy~iGi1vH~A-(_{;5x8C+&MRx;4z>JU=uEHSkqjM>w{W-fxC_rYrSl3XD(=_l z%Pa$a)6z~@?YgaZr(XCgy0m@iu8&|XH4O$5!8%mht<2N=1rVz;zg!fRXY9l@9o18m zly^|`eZ|pYr;qmnX>Ld-tjDX2)>KWGy*wL#eiff|6A-xux2&ZyYQHqWRClmUDViVc57*1mPVM!ECmJ;_Bh zcbwRq6a&uF!5Hg}Jj$@AN&`gjYNt8PRIvMqXw%}#E5E#kDzX=>7T(}SoL%KK zUwsVvA zXNSkO?G$yu`M;O#8E{s9wyMfz+iR0KJ8XV*fe+k3Nb{5A23qJfM7^L=T=MeLx4#n2 z9}7Lio2V&<*+FsYfpy@9wZMgk3~OH

rlugYxgo}P?pvSw}dcr;?-cQ(2t%NX-To8qY1nVDvs`<4 zqftL_6PI0eor+6$q@QW=qQH2OG0*r`C#!Wjn8Qv^x%2uA?ptGorshvXmCwr>loBQ& zq^>jhTt&ap?9}i51C5jqFQND>^erj28^WT6%Z(I=!;`#z5MI_e#(!=#nz6IDY;IJ? z>LTa29v_FUC{#99m5_H$?(AwD`87D^Ao9=PSC0Lw@Yi#(AASUW9>+Yodlt+@yS4uE z8cu744Crignnjq{P>9#E>9k8JmDx*C*&5&^zdiBN(x-Vf!Fw4~3>XJuFp0Jy?x90Z z$>Br0+2#b%i8LYX`Z(Jp3XA4cVEp)5cv%9PUTTb(e->;RzE7x8WGChQDY87$T3RpI9UuPi`O6&E0#;TbSD4tq^K0T}fCO z9A7(jx<}@gmQ!$S**)Cw2V{RNn`7Sevcr_9y`~c zocUKt3zZw1dd%6_v(|;Ez8wzzJ;W)y1WO4y6$g1|6h=W~n8g%kB8b(`?i1LyqiO9w zn6kLcS2}%L%(^rhnt?27r(#I|WojMt;tcCBKWc7g#of4;!u)iitxWQ_l`4f0SS+OZ zCHx;$UL&{yK5W^DVxEcR;i)y67u9KqJhQg6f8rnfFa4MCe;!C+DMtxH+$Wn>@Z7zU z!waBgAuh-&KE#ydbrPl|(DgK#u%Xw@qcp~yFwp2|93>bK`axWGar&}59Sy|!i!sga zqiOcW^>K<9X3cY;P6U#v#G`0>H5aAbxg=5IB-*QZy6BaKeAy4EO`OD5!Zbn1iD5Et z;ljm{q&lQmuxL(70HTe*Ig>i zecE-b%4tl2#zHa|OaT<3Z<-zPXtCNYy%rQEZ#H``@Xx|ePgj+v^alLNjVkYtfV=fq z5{^9^o~nM5?cdlMT}gq^;ZH?K`pQtot<$&lLN!3>qN5 zX!wS8MH4sL8Hq)Pz;|PWn~A!mf}9+lEkK)3*=<}Z_~UNZRzSh2>%ulb=I@JKvA?LE z!)_V09w#K`9(0T0TRnk}t4mn^L!V37KJgdTJzBD(z4+S6cx1Rz(&bjwHvJj~nvkEH z>vib}@d;UqplGE<&s@-uhEMK#Ba&U7O%K^t&yO{AJa4icG9H$V$E{_nukaZ0v=nk= z)JElE!<;dA%3mbVZnmmkx4T89aEcQ2kmFGm@Oujo0*&_ktn}Mu8}|`hlkesD+W4Zs zVh@?FpnGI&2BZD-nC86ibTCVwm1*gvt7#Z2z+=vKfmU7xm zsSZ>>HSuLgaMi_ehuw>Dl!-bLmnbodEKgi5f#b9;lryjH{?qUq8w4t=rKK(F`8MBj zzjoRdmfL(dEYmdG+|h)~p%N3bpLL42p(YN_Sg3#EOs{<;f~+&2vb0v2|5&58b#R=w z(rnPvCITNcG2dxLCXr-)Q1JV*mouXOugV-u(f4sLzNR!p{xsy3Qlnp7e_3_|O2y>X z_iiLfVdv+u@8yRd^JO??Ozfqtr3QiP;je;Hk-M_0OBaRKjB?k{r;9R-PVr~)kp)M4 zm(nQI&7L3mCNK|7OYz#l65kR8oCs3Cq9nwNcao-3oKKm`uAa0c9(cUKK!(}hFsnMY z8bm#3F8wOm%Du_RsnGb5#Qmb||7_lPY2p1G*jD)GlO-&d~y#bFH4~ZP` zBiBp4lRFJ-UQ0~0uo^EghwEqt&pc7-VzFP`-h%Mnv0_IwN|SteR;L(bSnU_WCdePs zbd;WK)jQ(4+oW)46ZMehY&wo1*o=s1X*%3$rMz~=T3C-3?I#uj=KWqMLtkUHbug1f z2lfxbx|ZgsJ^pA{g!8R#iM&1-4>ek&-b6kNtC%v(dXT%dE2!N;)y@sA-7Hs*>3-W= zo9HS`)Kx-9XGf80*D`i_xJ}-yTZTI)7OmkzU=U)2UUWR^Cp-5!F$RuwXxxv|!L-9? zrFgtYVQ^?dR!qF{K$J)o3JR>+bjXfTs%FG<0@ao6lJD^Cg>tZrS>)XsW39-34?P*%z`dcBPq@ckvouuKSo1(l;pP>DCiIq ziO}LX74Z8$jxff;&EUQ}L8KFJ<%L0p%|Wi?ZOxcgqUR|U&wIT(orAljM#J-{W37!0 z5?|Tk-}y$nIo&fqsy6MmK*(wvF`w!>wU;)Ntta!pJ8mJVXQ#UbI_u?>5N*Q;T`gsr zpG!v1LcJ%}mo~1L-uB{GuXdIqK0U1ct!e7^`K}zsAnm?PYjbHGW4C_PrLKTva4Tf- z{o)WP5ZqnJV*0aQq+L#SO$Vqsfm6$PIL&YS0{4kVY8Y|I`um`^wLoUA3c+jX7qut0 z$5@vMN8wqD>#eGXBEM%1qKP={MEgCfM zveLzfrJgp^+L^qT-OCfmq_V~6s{1MnI0|)RFa6#Px088jsjNHj6J%DB&#iEfDk2_` zUAULQL;jHY{}_fg$&9&jQ39S7q3t?Zu7$jy>OTn)4pFj%k(Q`i!bSXOBfi3;04G#MX%ksi1{e^Z&ElA|V?Up=f%Q|E*M80x z?rHNBfiMqN8(QWuFOd;0jZ6@qf1GRO;nW}2nf`F_1jejL1FA#iHrjg@R z)C+OPVu1j0Pw%qA{Zy^>9FH^zb>rn-R+Ln6L|BNw9B1UUNXpLveS~-DPdUm#(Y9iE zlSnI2RGE@oK*&^EZU3D^RzcIk+>|E6v)m$wa# zXj`PCm$i?O>Ta`iY^cF-7KkX%K*Z_7fAP z#bFfer!1P0_fk#Uo!$)u;9I;G4-I?e{O|1lR9cp7#**&&|`tRVsUPL+~)v$mF+_ovbp6t+x;ItNOt_ z;NGM5H?>e5*E~aukHP{0o5CS>6m{O96T+?2_m-R|TXR5bx=}dMpq;wD>ECC5hUtZsm`4tMZv?e{zbjL1iClGl&Oue6{Ec=RZK>|g{YAmC#TqJE~g^;6NNYkUZ z=d~SRpuzr9Vce~}OXb1bMYf0RyH7=ByXNzyi%=~-^=|K>lkO*%KnnNLHkU-4gPj@EIOwush5!uNCgAlL4P!HCE{x(IDrt+8m?0IT^Ft)<3b|Nn;XW;EBlo z%0y9#b$t!wUYs{sBAWxeU-LeDxWTt5EVzWI&zSDF68G z-zcB7g@49$AFZwh3nm0_lW91OT9S83n)6Kx%;dTZB8(_ym$*8cXxCHw{SR&JF_+%0 z+mpjg*EvDQ|6%GI!!qmMc(XaV$xZe&d9s^ovTfV8YrYO-sxZQIt9t+RXo=UmtM z{(RWaUTfX!r~BSPL0)$EVxP5r;%VBqJK|^NRuc*DAnB!SA$-pyA@e#&o6%Q)u0?k$ z!Y$T3?O5NYG{JgD_Ys#Yph7{apAArGUe(_irui|kF~p(2{mK31XDfjX23FSCkZ^;g z2hQF^@*q60xRMO7VQWr2-&l69yB^5HBLh%7=icOEW1%{CxYreVZV@kW6^RoAJ?0;~ zq`HnwQo=+51^9~;)9Dvo%2c68BIdzQ|2w|3I2e&-{0?=A#P=OS-5dNR#0sDznDw26 zfQ?$`xXK%6l4UhUY<@F6zFUZ%nifI!WYO((Xf5a3`pxerjhuK1TfBS{S6^{88 z-W8@OrLRC?T9TKtFhrixrqnGDf4zF!d4ImX`EjvDj5FKWKBjhZ;Jv+}-LzJ5W!bpS z7gW_A(VL0sczkGEo(~qRmi)SqjbBKPogpAvUY%0_Hxz*zg4l$Cy?c9P!&}tNyd7Ap zBP)(d&Z9WSyF}Uzm4>blobj;O72k;zJBNMcpZ}^9^&WoMQQ6hl< z8&)H$q^ZzTf&$E$61-# z1gLmafz<)$7VvN6%CBTI7m#RVoy%fbgQM}zpJDf<@jc9RZo9g}wB>-Tt92+3Hl2Vi zNv%_zy47*KBREX6uF{fzAK|{qwTp2c3zZDm;v3n(8o5lCvn;mdJEemyQPj+rpn!gx zEXZa0TjKuhk-w_=`GU)E&r{ad^*B3R*g|>HPOah>BW}gKRG1`B@P;D;i0Mxvy|zLZ zkWT0|c9^%^`=PRL+Hk?wR?QMl#>dGMT|_sYNLU429GhAOaV5zFwk7NDF{vdS*s(nM z9iu1NeSUhfwcUDtAe+X0y1%vH&Zd3J$`wRGj7eu%j(29Ld6z;gaXl-+@zs zguyVN{?6xb1(vX{0Haa4yfxJ(OUUfreDyB60NCRus5$+g z=4OI}0k6!1l4@LB;!LwIg%B&rPaL*Y(SJFi?U9`+L0+6?En!%r353PKlj`YM$%lOY zr4oEXydNF!y)d4FO9}QId>`DXXW)}{NDlX-*Y_SL&{-fzxvj}+ju+SAv9(`Q$KfH(CAi|@D-!ruqNiBLbazW3Sn2i{O1`YGgGzulgD&$W?S z6np~2jw@7^{u3W+g)5s@ux=XZZ`rNe1#PKKmZK=)ISq}FmtA`iTnieArW;AOz$@Nx zZZ(0BLKV&iXj0o?bw>m zhf8fWJ#YgpV`O|0`Ap~T?C;+#3imgY-d>xFo^pR*bj_heYFe)7+lSbO4YFaOW14@P zBi66Q5Ft=j=doiKrW!Y4v?}k;(ov>=zo}{UL1L_3F^w6@X*r2aZ0aWZ(}E!uW?WPX zps@ltKhcety8_bBuCoGzOe)_?ygDkE&Ybmy0=yJ1jFhSN;0NpA4bMc4y`~7w@=?&+_!z5QqOJ0F z=CWCiiPcb0^Py{5c}?mH5;>2xjn1h zcKI;3W?{rK^H9V~V<2l>$R|0-{Y zw$E%Do|hPF{>G`xaZWKSV=J2UBh1U!PCT{rGs$vgp+ef5E@^Ln^b6u4eGjRhlN}^2 zqmOEdt6H1vN0TBXyF+^-{G9{bwHQdF!cg|nBfTK($I(mnMmEs?$dWN*{8Li;YG&`J z$Z`U%)1W?`eVk#jw=Og06Im1b?xZpimXm^7aZF=VRGzhsq&r6#pZ{^<)_>5G)eV_} zYnWWW8nlh&6nnMz)Rrl2(Kink=E030{>5+h1(>-*lT&>gx z4AyU#gC5rTm5c+sBoS`;ysASza3yDM4L<*NZEl|6upO@{S;TgI{@vWQs19b-wixX- zMB^ua-rfWVjS}L7$#`F|Q)E+Sm|{Zwq!3627NB81FDr~hWu&tH4t2$o)f z@LX}_db(ju>8ZRt!AIa(UksWw2*DA^wSyV!Ivut%bX5t-u~IOCCqW75M~F_kU+_7h z99d))_&Dhb(A&aUy`UW_LO+Y?E04LT*e8!*gF z8mr1RXOo6BN;A%Dj+_6D&3k*fvw#8O0J94nj|y;y<_a32w}|HV*}z`xy&{Y`@?)-K zH@YX5M|pWar*`2H4m-POTj=MqSE7ayf7A9(qkt(M{O7*DKD0KoTnT31ozxukNb+}$ z^eF=MCBU?+Ee_v%2qKSj?o*=xA|3tcQKnvH?1zR8{l)YBhx{GQ9BRjOFMEx z<~t?g+E@Its&Q1v4B%-}Y!`A|1O1S57mIqA5DkUPHM~BJ|H$8|-?<-!@E96K(4|apz`AYM(l>_hl`Eso!$>yA zKPEM;VW2(E|_5#f1uQaf~kCq+%++cR)+2oEm@O0)6!!wI5XIUkHx5_8Za6e99ZP{~K z&RypXSF~HJMaBS8y;Ztc5mMq9w4I^x515JjOAW0#b_!0r_5NUy2&-eAI5lIY;;6+i zA>i8jQAXofA8(S)_>pFVKk7Z^?8vBR!OMATsq?#Y<{Ea9AR*|@2?h4b)m$EWDYR`mv8KQ~-4TtAa%XHSU(O6iQg)>I5MQb8-E(p0 z3>M;sGR-yVa`@-&D`+h)8X)66Rcl`z9s2po0N`?nhWiW*vu*lYA96o&O6z-V_nsl5 zJaeG3_siLI=5rqNc8`9OCU>4tNe;Y((;o3#Nqlp6cbxKU#5hG(u*2LpB?=Z&OSWs> z#}I!(+UOP#GjliCbr&8CibA9jG^FvtU!bhuK9u5kS&2*Re{S8}+1TqbN!Umc*tF5G zQ&E{!;%tGAs~#7=eG`=1G;AwP;AuZDHJpS2%bLk=8LLdP^e}9M=2tXW6El+I^s%AThN;X=eHbK{!hM}w0}XEal@ z@`y8N0F^}SJKvZWvJaukq2dwz0PnnD*7(I;Q*KW#CTmQ~p17px6Bvb_zTVon&kh%o zT}OMyO>@t;b#9F4{AQb6d(WZz#^XzcvR~T|ExC0oY1dpmQc_v`-|u~H|1B9&epj797_Yzu&-|S*!TtWh@x^rJEY%*4 zlTZ_hX3j=9?#H>?n-W^qx+}L9vYheG4|AJ~-f=S&o~;qDCPm@)sWS|%J61Wv1 z0qR0x{;YGhB)A>F29+y?@|bPr>^!P-ShLlq^eMZN?6?zo}^va zb9mbsQ_A)HFjj9h)XJFM>R(W&BNWVBRamv8jIcyHc&Aw2_howmW;pi(OS>a@Ea}QP zdsLf3cB?+F5fnuun9y=AVUH&Zyw)GW7S98l7E~)+e?W|qS^$qAJwp}o)mUN(eYwJF| zcJDxGQvI-H%;`W8_m=JMIA@0-0j5ub>6+^n{Zm(}F1HLD+@5gy(s022zDmcV@Uf}_ zdWz*!S>KFMh{bty zxz5~&#S<5i=v@cNzzybMwvm!}4ndGC+MMn+QBTw07kvPM=}o)C`I2Z!bxT`*)jp5U zTCMKe!*0hzTl3L@?#vRXu3I;RD=y1;f4H;n9_|w^*=E+`GDmY-6{9Yb;*ZxB4@$S+ zWST%5k&vH0JVp?Wil3ZI;m6So3KbpK`s_8~X4kvk)@Bc6XRc}n>FqWEA@+y6HjC@h zPll_R(CF}obL7J!O~aH=ze?7LgMH>^mSs23??XqdtTx3>#(tL*UXZ&u6Wwxvz@7^D z_+jt(bmqY~33j-quf7e)zXTi%G?fLm8-Z{CT|+R>VYW|}_6P>pfg;!IVZES@tPCM% zN>KgXji~%UGkx>Sji`MDaLRlVWiMjr$R*=qVxcuL4jU`9y+3;Ks5e1j9b{0+d0rmgOu@F_#@m z$hXFaRI1r~o5ahGF!1ZMLTKVrhy2Q?$$VZt+7~$n=HJ=pCF_er44Mn@`)v%gPdiS} zH7;Tiw;xb?2S+sGj<3C5+!IP_&C9lvzFyFisof2But*a1IohgI{!vEXh{^&5_ByJx->+0*=MmK#_qN zbFsx_g}ZpMWM0k|iC|&BeQoQX9ZZm;CFE3wJ+A&~X-Gy3C&a{ptt)|;ZVgxpnzm)Y z+upAVPH9F!j4NPg$_Tc`3DJiBl2A9l-=@uiduMdw*`W{kMvSwBW>qYg!sl5HB(r*o}2W zmG+SLvH%t@*Z1bm4h>#GOu@B2qX@Iphh}ra=tP07POnUb{chf~fbD>$|1ILSDpW;w1iF7v67GpU;fMok|a{j4R)bO7)Z% zd>u6gGxByovjWtlEW{`$Z~DQPM&cioJ4&3MGjYf)W4NB>KI#f)to2%^_{v=!_k?CK zW7DagRt-mAl|)=R=KC##$(Q?F+B!}fVl=OQ`+FxvD)qMgN&-veq_$>d!A-<4wP`lE zdOIYN$(G|p;6%h@o**DTHSM-wVb&A_*8K|18qJtm%`0BM$n`Ke7c@Ge{ip#h?kv;#MUz+0?p`!@&@h4 z{j6@l61mIqRpaV2>tI&gqR5(gcE$md?L(WtMre%5yW(K8k(-4nrEim{?Q+zco0;G; z5p!Kysy7`-hbMK3tuWCU(N)AFi0azUebL5cUC3h!(SgA919pR%Lpe*zOm?r3jvtw8 zRDTfUA&vGxyO3SckUXd~fnV_Ima6>xZ;5Nht=nwRAOSlZ(otB`9t$UjFjg<}HVr}y z>${>30>6r^%}eKLd{7fMuN`2TUfo1sbwVfa-5T1Zt|{EUG>o=mt@#uGQ10P%5TJ7E z9vWBqPpYl~^OCte#s2%I`ku)YE5->n4^0dI< z2RB*kZ8P4Xi}RHCg8}L#bG!rI0Q&>T$@%BKN0M@1!@rf2XyLiuNH!yNjXP@8v7X*e zi+HfQXWD!QnBF!&9NKR}Syj`cn3jcAP;hU$6IuxSF@A8!=H}uSX6NWk85Q<(A)R!|HE-h= zfl}MyFHe!e<&b_~fFMS{j&ae4!lC7&R;_B2%}ZXZ+w}P?IW!OTPgONW`Sxp|UadCj zas=b!vTs8+@pyFtR67_c8_BE(?xap@rMSJgC(Cv(rI}pafzo<}(uW8tWffqerXyt5 z?I}I&VM$wTh1{I3^oi1o(;{|2i4~?AW%rTJn%8cw?tm{!x!Ii7);MqecwhZ4JI{2C zEeZ`dR{xxvn^l%_KWxC0K5VC+OEaq;VW;HR32FjIAz$@(>I<**4W`<9t{ITK!9{Uv z`x#bzbg!?ipWq$@r1C$TtOl2wUAhi2lat5s0xIH#n~8d(7h{z$W)H}GMBH)oRC3-q zZHex;-#w=knCJ!tV{O+VaOIZB;PUW*3+p}`X&?kW(SeSkpl*3)lW@2ZcN(NY%}2mQ zwpvU%MTJCySixg2t1H6k@6!H&Cr@Y09eCw|2ypWNE5(w|qjap-N1wvx=L~tQS5^6n ztMUX4v@XD3EcJ=_Y;jV=*@LqczH9Y?Ns-7AyA#a5btjm%oa21vi&=7P;0HTh*Sfn8 zy;a`V!L>YPDD`?L0d;!oE?KsNEH#$|B45*jQtZXIe#h{H9g4bUTe zhwIlddhtNEPCR;QtqZ}D0#KmId9*_5C1fYfzEBB&i}C(m(%Rx%5pk{%^A9Gk)D-%> z!_@M=mq*b^_4ZD%N^8i~DZZA?*Ej}4W`s%A4dx(r6rQECw$8Uy^)4P-qAF>k!*_OM zjA-}|a5b{;@6GBZ0L2$=f;htZ0tecpiS?c!O0qY!2f@u*#7v1wKjo8k^BNRQF2-TO zSz_1R=h410<>AN(+T9TIedDG-^9DOw&r*8$0L1j_R#}w(pF3_6iWODPP-kkz4gsD? zMY%OIVu?YUulVFRk^1CyyOre_QEigEkU4blHa|;w{DeRigkw)Mvxue_J#F@GxF2!x z09eh@&Vuv?;1|7IyeV3Mjqk_*&Db7VnKk!wkQ4;Nr*Jjm?kA0^P7q&}Mk4=wW;C@_ zLKtd=n9{1~N>~Kz3q-4FB2*7M7nfINov16Qm6BzWC+NM*JlIq086GMOb-Xd=NKM8F z_T#!Uf)$Fiv+$huTZ~zD19&JDACL7roG(#RWEt(-0@Uk6!RD`RM%{xa2Sn@Y;9^Xb zHb3YGPv&p#-h5S_r;Wxd+>fO?bMUXPhP7k!$*6RYV0B>?I!=-m3I6;k%K{w-Osn9R zG{>u2i>G8_xnNTSg^mQ~;JO)kZ+^epjKKBM4&5T3Yb81B^+;NB*kpd+WGB_e9c zOT;clX|LlzWGE2A($U@)Dfp_gk(5wXd>1#$t$ZG#qyJg|FmJ`+D5Z*WAETv`m z4MUHnT$E{9l5Pb?;Hx2g8f=i@p=Tj!1{P7&@$VV=XHm3!#^OC7 zo)#rUI3#7Iuh+-*DrJ!?1*p))(pH~)itpA-@p&wwaJmFx(F_ULh|Dk;U_HS%~?eiI= zok&{s6M272^afnqmQ&>|~RrPvpJ`0wt21mS4{AL2*#}ImqA9-!# z4BA@OaNHP*k?a1RXArGh`_yYCmtHj_hHb{5!MZIt!2L~}GT`TK>v#t?q#y(1>>m}< zT+h~^TA`GgiFX{z52zMmZd~{x+#qu{V(~BYMcKft{$Eb~eEM>PyonMoGl_&D-@h~s zdqfDuVCEiHm|YEcG^n8*+zaZu>Gs4L@&OJ&P@#BN)>2VA3z%4PNmo62;ocmxBCL61 z-t1us5Ev@{xR#*edjll6@K_Gchqga*HO!|+%}X8;5WWm5BN^qd>x(zw+uTn{1> zQeyYZp&ocC2u{wCNHd>z+&A1#as&pdGoE)9!m+qxX+!rs z$8E`+)fg~0bHnT&kit4_X1%^7qHRYiK)pfpcY&NOJfG;kJxH&nm;Nu4I&q^B5SSt#|wv$Bv9i+bEb$nnK5?}5bVkrK)2$xR%aPm0{qt37)E9ME?5WB zqZ$;iN~?^J2skR3P&S9Cz6}OAiO&XWuUP>G0uP%dX&4F&BQZd{JPG)KfI#4-nKfIM zbc-%ME)iD#ddJbNC!ks8tlMZ19yz;0KwLtyjPqdEd6wNP!Mf|FTSn>LcKH*B?+c97 zipvp1VMCA&rvS^oXjs_FZ&8CSWJ~TR&vdJ8M}uPm)Ignh?kv91=94N67qRN zZajz_)Rj;-?b7SMIh-hw@oBaE?%B6J9xZ0HSWOu$|%||6W7ceDFxC`#Jq^zBZuJn8xtER@8k_ z$@!Dxu_D$7E#(ekw5Z?{z^Gj&cCQ~I&PE1#XK5#@-+!SK6YLKqzk_su zh9;4&=Y11GgvQz@$PHlk{rS5jb^Oy~xd^5Z1_A(D*&HVhTN%z>x7Kw;kIdsQy3|F3 z3E^pJM=$1n$T+lq#MA;8^KhYlsURujgHPz$^-{L9#cduL+mFP?fg^wlp|h`#HTBI} z^!)-UE3-Yq_04o^JS?g1Z<}pqnM6f><7|%36Hym*i?9jh*7E|_|618?MKY~pz%F;T zrTmEtbRyd3l6A6U3YS=1nE=YEA7_kH)cD(GmNN|2i6$8iAY*xyiJL@d=wi$p*34_n z^51{KuQ+os91YzOb+6ZfkT@$If47p~B^`hKbNe-G$d)7zS7S6mX__)a+_#9%wZi@> z8@Q^8%nbcQIeRn{v@S&ecn5zP3tc6=gXK2+ub-|4GLZ5HxqIvCzkuXC?!0#zPKHhm zh>aJFh?)ITuACXEy=C?6^vljkd*S`<>FmD1Nw>Xj$|y^QVL_kwm%isGE7jEj9icP2 zZViqNB@z7D;s17Ho$hBpR#CMvr5{5D<@MF)Dj&geYyAcOYanDW)(kt_4R_gv_lm3_ zu>}8We-;F#w^k0NrbHC(7^BEzU5h%MI$5hu5w>3*1h|Un2j@(G4Sa?h##en}1El#l zAq5QE;s6y@7j@_Zj(-9ZLIi^wfbjcivcU>LKyhLlbhUn8IxyCc3l8W9z9#%7V(31u zN^ml_t!Zo_UBO%%D?=8IAUeiVdCpK-OfNp~d;Zz&H@c1Qs=hCGhU!+=8+XVc9?fmI zd?0I>w0KB@Y3ddlCjB#kdWyTEE!e+>6K+6d+9t-5S+O31B`6@ZtbTcULlh39Gn72) zb@)HC3l3eq*JsMCdIKNKtv}S4n5=W6Osc!>F*FWF?(r?RyAv6u)3g1F4pJ{CIFPU9 zwVx-3g<#x2>6wdksJ$L=k_G?f)w2J!{oy|<)oD68$Tz8)`SY5C152g_=YM{Gk%T8k z88Nhme*PciTNI}!>oMvbybzf6)eCCq2;}g6R?yK&i}X8D?RALP!@BnQ}Km+wS?J}wbK26y}b?9=h? z3?COv@I=f9;e@;vv!uZ`sys9e3Zlu*ESJl-kz`**p5+|RqqXhms!_-7EEy)7ADf=o zCJ%j{JiL9yNx?O~OSS{pwyh~kYWph*77RQd{X|x-dCz~a$O+$nrGEy=x zySXuVI$z_14;;IgtkxTtFty!PZ+sv5uvs|?x-VO`s{L$8?FPiyy7_1`Np)%8JRvV> zbou2@ezkaLQeo*X#9jaSi}Y>WWv=s_e_5Chb3Cnsmu*+L6XojioWP5|<6y42tj3y; z`DJH}7c2|%YpC4DD*2V%;fPKRuw|E#JQ4ZW>}Ai{5fDBiEOlk!U#Clp6n6~fHB??O zkN$M1VKtV^#%U9X$D)qMX_Hr{arU_Sq86sWhTfy7(dk~UU%35rsL;C55us1f8B}w# zHC^O|Y!{q)_X>6We=fTbN*&CmY(P&idT>1!#U!PB_^rsq86~l_IT0wpv1G;l zVxFc3yAL=Zc9SV`6abKeZ3+p13SADGU6=kXo}1ec#+*hP9D^@G4JfzVPfc2hg8W|{ zqDVIbYZXw0M9qVN5956-7Xci@i;vy6j*b7B@ba5*l0IiG>8^GUEKH@EhB=K{SYB#- zK-I~%;#ZWfG6@!3%(8v#m$h*jX|HKdi6aT^SXe6IM}Rtnh;@hCms>fE7O1Iwa1`|i zG*GmG=I};1{8uh;=^I4NY}Fgm=^$S%D+s+99pkXuCCbtFmA$Vu;zy6tjo=RyuO~o9kpd1 z-@y6VsUFml7WfgolR1Q!Y^i-FJH3x7=)b-Y-K=-=&TR6n{s070&C18LwT0sT1^@eC z4QvPSDFQ=bQx2hRv+U@jh?_-#m=~PkxA?p1a;K`60TCUunkyZWq0?G&FMXi@Z{gb5 zzSi5sxng+0YA;EMm{bT*s6~pXyqAh8W5@_W=^^f35Oa0LUiOrEyYcfD2j`E?|2*eq zL8pinOC8QCKLtM0BF9`3OL2t#2?YN|+1K@z-I&SGakg^NKfPj>1D*7*?Iw*2!SJt_ zl3fEOZ#CQxMaa+}MdLw{Q4hvf_xhwhci6R(dE((5c4cwMx~+l@%qhU_fY8HJAe93Z zW9!>J!XkTG+j3{4+rk@bkYiraS)_d(|8fOZ(dL{q?k|et2LsvowGpxN zD>-Uehu$=v8e#j;xwOD^iwR~Mt-JPhwesQl;A-Z;p9tf_C3%PW$(1OP#NRg4Orix9 z?jOcwK`y23^Cn13X@U5^4Vi102oVBgyd# z`Zy{9ykV!NfA#y$;@#615ikAm*8#p*d$b!al}m7vVZgd66;)2H9nnTrB_$Zg7h1tq zmTn=@u8zP6@lo28SGWWV$SU_9<_`N*1%H>Ay96mMK9bgU zx7IxwJ{3zBaA=*OhGM>23@r2ezwRm*oq_R{{stPmaorN4L#BV1_Z)~+s0>SDz3lG9 zf2tPK@%;R-BHMZlOt#q9SeHLjkWcvCf4{8FSYU{dk^41)z-L;@Bb*wN%UfA2C*0I6 z0L9=Ox}V_LUWT#HGx9&g%J<@DN|@ISH=6dAq@5^c5cuq}@nrG1Po`@dk$#pwqkKU_ zN9+@`iz3bRS5UAs=vD3ce0}j(TM+)zzcv0L$3GRNaWYDIfZzx+wx?g-y8>EiubtI( zS{jdK;DAP(Kbh?Uu0<*G_(W=mN5ZO-ekR3v7@?$&zW|)`n~B^0HwVY+*@8A3>2*vO z5mCpH!`=U+2Q)XeF-{BCa~$Yx`Q=-L#OAl1&i_$xv#HDPEDsr~A)~y!DBu2oir4ui zs%?~QBkT9{M%q2zPP^747dUDwAfF<(TbwOXMwbIZ>`glk<$xSG+ zMk-Oi)%8O5G`It9X78OkP@W~2JLmm%U6ri6r>;oR7(oz4u zxh;?ituy4?^sqL#sLi+hXn2M*_~H!J&rW^u|4H+n=T;XvM+;5zWEO#t#i^3GGEn`F zzYp62%-%mAfUrIg5}LVY9m~(asd)rP4=SC$k5(>}?s>|qX-Rop8O@PhYeP$Z)6$~W z&dnb_XL=Tj-LR&LbXFqF_1#DtAi;`U^e%4hgK!1Nfd#pi2*-op0+c4@2JPC3m~1x| z3)tvr*IRIk;Qza*fUjBw8>0Q%$Mx#x^C8`oXFGn4*OgZ@1oQR!lz-gf`G_&qWVX<| zn5Uzc(%*`;f=zyGSjz3+?rYVs^mL{FC)AsLy(5w_=cfuJMES#GR)-yI)j@I*p4}l!HGBU2-Obg4-o`A=0vx|LxsG)TAxzP?usrex$0u!-WAKnNkIX! zaItD0p4kDddZLaUp5@qDR@))EKUz80qyp7a1LOfQQ=8f-JcU` zykT@cVpwJh70Y+lf(!vF`3kgq`eTfxH+zAOa+VeldzoSo0?WQv!hu-T zr`;O~Y5^fg#>b+DCK@kjlafM&vrD?iPrd`t0PE?esoEum`7xv9pRzfzj`gju&ELT9 zpf)c&B@N0(6z{|}?FO+|xjp>XG@>18Eaw~-UQ5J}zejummIz60a5Hom;ctxYM-%vT zIy>BsI(}OQd6PvWRsH$$zuP#s1s@i}7ip8PHk7ry?PrN|$FIlswJZ*Vv$X-J%6DWv z8~*3tfT)d0Gc`8uenaN9cIIl8XlBLoJI6cvOG}wfcQwm%!j9d1>%eI@1xr$D)m{1X zTG3F;imdZsosk}s$-d62Y&VJQVS*(;P zq#?+F8a~bFRTEmf@&KPP75b^S@ZSqGG<4FR0C({9TZnEi-a0o{xamjOTn>&ra({P9 zZ7X?s-!mjgJaOq|Liti#ifT^4>$Yrj;uJK^b=enmhsi_?bDHQSOhwnczd^OP*SBCN zBZV@Qp{Mv2sV(OGeR2FE3J6~uP1KBUeV0_I5dsdBWI{Yv6n|lvk%8IV!nl;nC~v0| zA^Si4jv?0gCNVMd^dBAJqx5Ply};;z_y)!{rzGl&lq|GBN%hi%1OC5Xo@llv%lrK0MSE&pCtWoVAinYpXZf|2Z<$$hUPOr&( z>g6I7>YS|_oflgaWHy=b->#1~UWG|jpBywiEm|c0%H;Rs-UlZFt#(d(Y6C>F^zl`_ zTy1(35=ufJS;AWV(P#oV)Wkm-mO-dn?kkf93j&aWXTl39Po(bG1s)U4>`CI zs7NIVUx7DPEP|EINu59PA7tT;1y(X8J7Q%o-P)bl>K=a>U;S;KJQR!KBXmiD#7%9E zu#%2@sItEI#_FHtA|)bW8uy|)>%?O^4RS(uI7JpR=nTzo%i@0z5%VaDYdmouP)ddW zHaqW(IRV8EAQSH7dKIn?6M(X4vu?a9WEF&=io4My3w}z(k|XT+Z?FN)e2Q9uS|cTL ziUIE|o6jV@rE#zFbg9xqt4mNTEg`wuBu`k=OV+JO3&#=c|l54dy zmAsV2uMYFRYW1F_4Ys|T`J#(&NsE06^V4QyeIM@{h_~_3RyqCpqFZiS2S2Y|{SoIx z5VX}KB`hK{LDLcVCO(y6W)7WzncsFYULOqy#I6LU-$b)Bx{wS1lei@-Ro*C876=-D zpa7oUx9nt&6}{R~)zVF-2wZo@6I~}K>H3h_+>y4URtv6Awr&%=H(IXW2zJWgd8;#1mJ_Prby;xbvULE!&ONHA1y=7`bL7pgwbNe zW6|xV-#EEB}Or@ zzYGx^X%7D(s%Zko383jQU}sP!=CRj*{Qvb4Y}+x%kZJsol=gy-1&w9a;!eP~HbY9`(trxq@@gp~sAk2iz}_j! z=tQrq>ChXg`2K*_4$^zKJL?N z@H=FgoJ!uK!6(>(`~v5ZN(;zNfS1PCKbw*8vxjcCV?ooN5LKb3HIEc0<03q+0bd|D zx~-|Knqc%^!Qbkd99}o5j_~id2rf6@ z#Xnv<%^$4k1j4_-YmZ&mcmAqxvdTLAT>np*VW-v9*g5^y->qMu(jhn(jR^5}{Zdrd zuG7mv$fZw^3R3F$762IrTX&HIN}tHoXVPfmpBsC!C&n`_^J>n(|__} z0lo~kL;DKZa7r76g&ZWq<{~`^Q=9g>EAql7v-j)Irdge!7kxS*p`-s=g2HxPCc?bj z@E}>!&y1ZT?yogEAYY;17U7fhNj#4tq;*VW0_Se+)QvZ9acf`4%4%+%U9V=TWx$EG z5*1d3HEDoUCR+Bczy}X|0IM53v;4_j7-sWb$|Ad{usHj_7j=eF7^|Wv7afsi|fISY{s@peyqT65#WEfm0xTb z4*-||T!d2=ht*Wt4?z0-SAqs0onZo(*m0-^(nKVUHj}?8w{T^Y2py*K<=PUZJYbP< zAGufzS5hTaq?POwNxB5glYbna5Wy(NAC>DrC8$#`NXf&LcdufeG;y?Jms#-sTkU(- zZXuxn)L&($KJU6)g^Vr4K*@oz zW=qBgE6v8G9&gud&EF86p*;?^PX1mz!B9eh=_Wr^BB@I`i>QR(9=Oek4UtWS-pvy+ zHFyIsNI6Rnhow3s?tj2ZOAf=TMq_q#Oa?nw*@(u^028YS7k?PA&RdS*p&iSQfN=IH z0{5p<-ITvKZ80XLq90Uqfw!dc7RKcO za|M@2@k+9*=oI8*NgXwr$3yQkSx}|Q$PCxHQl*_qe$hTk+c^9A{Sov=4Uz`?B@5r4RQg#xE0geFkHAX~I7q3InAREuwBPK) zYF^KIa~Q!8`CT(-LH?cSM9d9E`u+s;eN#`d4X1SbeU*Z5`cRw;H*?izDT``ZbEU^M zFrH!}idH!rNIRLOfv9PJEk@4H6Wq4hVn9X=V>9Hu=t7pNbgzbtmFFRWdbDuZ<7P=b z#&p_X%*V63F-p>tRS&7T#c0?~n1NJtYdkwVR;{9fD*!P1qk8x@+!cl$L-9az4nml; zCFA_0z+j|3fG0F-kA0KT0}?*+F2@W-(K=20(>+t=Ccs*uEV?rJL2%EpI4U2JAPP46 zFicV=NNXs-sLaW#=qSHx<8pTVrI!L!%M96{W;KdZ7W~d=s2aOI5sn^>`#gGWPzY_9 zeZ=q6WPW%`kG z4yM|XYVtZa%F-wbHNdY{h1s386{YGW=c{O6A$y~2OYdtk!U%WVVqEzW9C4@7~Ffrh? zrsBVW>&x<2UTqyyrototR3bC0*Dh3;FWJxDdtzTKyL$2TA!Nq##wcrWCVoD#WwWmq z{%VE^^ufCdEGEYCkc?hn6(tgUG)~JAH<-!$i(AUeueeP7wZ+75nHr4P*k37+D^K}} zus#E+Y17C{;I;TWxk$%=T##U*}Wgs3>O(!6cJ<+9D~ktbAQ zg(@8dlzf?^1SDcRF%aw8*nq-cdO?<_HTov(u#in1q|!~42sBxI!0VM3X1Jn{kz@w= zG`_uf?ce?4g+F4!*g@DVI-D9&$(kM$a&|!(ZC!+Z#3fPdT}EwP_-J;3tD&Z)b7!s; zA_L-|g9yYlS)Fa+ZZeK+ufbcm9>`TGUP+{w{cC2}{w2yIdF=|I3Irz>1mZt)AOtAD zfsTSv+6t|H>1K~#KQejd0xRgHa1lke$BV!6{<1F*XO>>k@(Xk;;t6&iSP=7+#d5`Q zmbww?_pON;>e9vB-qSQSN&M0c3_Cff!HBNvJGPb- zaycCtME4t}2hd*UXTVwJ>@1ZJ@!!0js>&w-V)r-Sg=}xnFE6^PJIh4BEDMWIGD`^q zx1T;vJQ*ncjm|D0V8cN(~J~9(clqz+DMmgoLtZ%5;AxY|?8`b@;aEO&I#L{5QN^JzqfOU(Mrru6kK;}Ef8k`W(`_jtj3k4R{JfsnFZw4(9 z&})N&JJtNMpf<*V`Q)y&X1SSJ1sFI!T{;~8Mhd>4%FO+~fWkl-8oQD9nfVIrD4Xig zdD3IRdFgnBpd?`dPqsb7*L8DrA+tN>h@gtMCgIC2Qz@YiyoAbn`BvxUi z3Ii+9s1$XHTiOHyaK#9Nf$}D%H>%{yt`2|UKr?Mi5c4Mk5L$NGA5)aye*jQ2D6g^L zREQYqVfo)y(^L)$VLcnhMW)INz2#%Bk1|mQ-kaw{S~$^->%`TEECyg`k=mromY%Z| zFdCwhA~?I1Ow{ZnV+;D?6Y@r~a#7Up%>kO9mw(f!e%k8f2}YTg^`)5-P3kKytjsz? z@rJl|>zK}S{L&-D>(PZE;p6mph_uAnf$O%lDanQDUD5r8G1$G6S)e3u@u2(L5C$`7 zY6qXhzd*AWrEBNOM^-1x0A~QcKJh^G-z8sdNLZ&^J(Xg|{}Mvv4x;fks^5v*#Ax z0IbMoF!`>4|6RcPT?DxS&oT|tP3>iB3!o+` zMULS7hE0di&NA!mw_*s(#fLpFYy?$`^^gNZ_rg{k&Q*dK|broutMfnI)GRQ9TM{gAQ)J`Q%(=w9U+hp`6 z^_o;PreS(m^HOp^fqnylSQ9SmZ((ZNYN2!*$fIw|(cGH|bKtprmd;IHpl9z*DvuYI zqAe?J)O2%KNxBWU)6kv$D&{=qVPbr8a()~pfOFHU!aG>mFt3!k9i=SCqxs2TaP%O= z!gMxL!b5NVx;e$}jEWWE;7kcO`KXs;z{cum<_9uFqSB%C9J-_M>U|XU)Jgmm@*AYI zUuLtM8<+;|!tI>8zyraBEP@fIY$q#cOql}WW41!($O>+6Ng1Adga{M#%0=GbP#_Zw zLCVKjGJ;K7vIBRq6n#W0y#k$^7aJBN1SAa1#dtNchK#71X@EZw&3xV`lzC9`oU9P_ zZRG)8%1 z++4b;@1hvsdKF2$r+lr`*`WMw9z>n%)+?XWNz^8rLu?o@;^M3v1zoTv{Xo~rJzBP+ z&kupigK9NT+i;l}>cAt?f%e(VJt08Bz>2m%MIt~EJhOQ7ki)Q%)9LjQv@$1F|M+`t z4>V%PiKAWt2QY9dGQCX$1O)wjRiz+isQ+G*`UzU{o%62+1&S()f2&hi_eTY4F6^tM zF+mn3o3G=82P;GZSzIQn>fk8Cr*r^|vDVjj#0>hf>vBA@4vW=fBA;l1kn>a-)uU_N zoAc#P8nQM#1u^ie%Uum_+o1)M<*=c;Nrrt0^D>tdL$(p;utZK#NNC76-p^!HWR|;fnH5& zPze&N-G&VfcUgj-TDBSHO(Mms{8Yu;)WpW;M}Q{pokb5?yuFo~G@{q#!!vNtK6U-< z=7v@=jKMtLQvzS1re$~a{Etam_nR`2Iw76it?&dGcrtRs^uBpfuZX&?GwpAu{AFJra8HgK~UJ*9s2E(&QZU&A(`Z}OZ=4A_!gSEKme=fCep)5Q9eCWL(1suz=GID$ZvJ;`P1?5E&C6VFst8vgbn*PYA&R_Mg5{c?*T^n;QC8v;r9YQB%oN7&$)i< z_w5R|I^N4>I1YSzuU-CmG8U2qdaZ$Gq3sBR!r`O+tL2LlZp*`K5VtQkB|=Bwm6e|v zLc_XES=?%Y9{~t`P~=rANK{d#e}I45kIzy8^;sbkn+o{;V%JIaWUi&}zDAQS3T`Ekpj8>8Fe9>{)-hV-`?s)K(2pQhjs zafB@c4&B;VWveOCqU;kc$e$>*OD`!k#=3vNYM$of-}T$MA9UvoXoR{(A-{3PvOH_$ zL%P2h*Lk7BHB~3bbXIuGSL$?a4maP+NBgE#T;I!Zg7>8naEst7q4vVQBBhg7;?hIj z`gKu7cLzRkuPp1p(_(7{ngPDGZ}`xq5C9iDv+0+w@oh2`bARgIrO=%{sactaLrr77 zyRUK-SzH0AYiX&i^R37SvAwsoDpQfIAAV-MIy3nxuBZmhW;NNss4jk`FsYR6D(Iuu zSm&j$bgG5M)#-q$!e14yxj)Ae%NxVGaP*J3dM#X`Rt|JNt9 z<)WTt(TQo=flrJqC)lvV_VvOrZ3OEGrzYkvOc%y21%<Fs z;OmA0wuQ`5)rG08MzR*v)o)Lwih%O#e-sx8cZ{?;`T-6Y3AGCfncMis3hNN&GYE8q zLf-4d7F6j$*W+?Z-uS4Es-jv?PS#~PsVY=k1S*)Q6iXwYJ+sad43HS~e2f?~M$YRj zbGWSC)*^_TFY~)UjU2D%>-}R?-b|c)ehP$CaW*L#Emm;4V?uQM5F;GYhz|7T(5q;$k1~9D>_564M@`Glf zeCBWR2#-Yn6p1K(;3^(xwfg@D(5d7Z*q z?6Nsbi6@U~`RUjBC`yz;glfa5Ct>Xh)eEH21=QbK?zx_mlxuN9wM?et->x5wnUw9J z7NU!u@XhxQ{hemcHUSX39K@Z+lnyAk$L717ksi%;`wV&Pn8R)EEALM-S#S7^%AZ(? z-MtRk1@5m=D?>x}o*wUYO9e2%-a}PWi4v`4R>I#&Bm!DD{D3J=M|qWBq+V3FQ7;xwmm0lrj8(+T`)#rJ-Exe&=ow_(uCKx4V_= zcHVXn?;oiHvP{&@b_S@o*`v>lnoQ#4{KQHTzjRROzg|e@0kL|K2_y^V-_jHAIitT@ zzFGsiBem>G?1fe16N?Z$XDm^mV5?t&Kb=o6i)xD2eRAm0gbAZr`$hF;0O(ux+bwTm zEB#e;KpN~ADg|Ivq}Vw(1)<8GYlS@ONI(Dg6{%d&5Ef31mGY=|(*_Pn%`CVJUaxsnlUUcbIYhPjNQLmj)`C%U?fEPBawu=ID`yqM@Jz*kq{>K;a)^Zm4?*Z*^< zVwW%M4}rAAeK`iGKdC$0f5Fk$n$aGwHVR$U2mul>12D@ve*LkneC$M}aaa_yBql{< zi!-b0xjX1VpmbwbeY_V!oi^~>lto4@Es?LiwFmn zxllUa2Qd%`1S&qS%1XEJu4f?WQwUI6r?RA`Sh6=j*T;3Leg^2si7hK0|CG`};TQUV+L}s?vTq#Y^U{zSnOiqfNMx4$_w> zy(96Lmo&hP|4(Vl3K}XsHlG$LMl&S9E#Nri&U`HA0VD`Ftt>b{;+*$ z-eTPEH-KDj6XY+B2MMZeTI>I(NRl?k@Z{(j)j-oEqli8jBLa37JX*U!_@-@@p?5LX z;{Yq(e)3af8UoRa&@c$pgtEMqmKzS*PjpDnV{pOLC;-|KPEK{S-Xx1jgXx%WVtTE zgg!81m$UmS$Y1$$0FP!K8Dan$E5yDVk=Ff344a#^ZF(rFvPQpYIrgI8&Ty>5ubZ?! zt@oJ;C%i>=@!17GFfz)j@B2t0+iPX_L%HrSj zPemk7UpmcuIGxe)8gh!1#)Y_B{+|}wW-Sa}2SaO6BtTnspC`S6;Zl+e(R|gjsX$jb zHa_w#F##qGEnx)U)`ilZ!s{RGOgEjn=+C)msf!u25kra!Rb2t6(N8&s$3XsQK&0w^ zZ)KO>z=QYoIA3*AXO>~tfz~tTYt!gLK(JS1IUMfOIuFC!F?1%;V@6FO398UQi;Dw1 z5a|jZ)U&z=^>72KhSWdp7?gYUR8NT~A6eL#0RRTqkOA9=3P4X9JNp}$5229KRQ<7< zUYK0(!MHHqWOGxS47MC8ScU4ZA?-CRoNf{~vP)HUlNV#!quXxB-fW)a8z#eLcone# zbUoG#g5k!KSl`Ju$zAR*pxL@e}T5bp@IW{G5)N6#V&=IV({+6NX(w} z6outt_^-pWn@yM0JoHi>7+XBlts=_pRh$oIqLBPNZJTQQng%Ff1NsGui|kU(8s|vR z-c;&RQ>uq|@lI|Y2%Va^{DoxmYpwicn zio*8WfwOUB+=2N7U0{U1A_#EeeAz;Pa1HkF7Lwf3XkGrvA%?hZt$Eq{8dq&B;^%C) ztNi)^#i`u20f)e^9E5>$z8meaa^S8+`QSOfSYww{W0#>i07amf5#VZ6HaBIT(qkq^ zb2|P$47|3`!vaRG;&KRZd7rIeNB%>MStH8}aAkhleVP$3`I8|=7tf4Cz)O(XqlpU| z-2f>$)hA9jafC^qEkIoPJq#pW5E3%C4ARlKRN*-wBy19Zk?)Ky^Onxryd7P@DLD56 z91@of%P>qI!%?IrJ~QJjhFYpGKg4LiET_3mZrMzY_aL`-s4TZJ_VM$Txx{dM^WG{M z&JgC-?IL|Zu<_wuJ77V>V*&?9LB07Ju3MPa_6)HsMRh1uQ$=FzAAKKN`dN*9Ly-On z`w!Dd*aPr%^YeNUDery%v)u2~Htb7Gs~ULj)bj-i{NFJ&i624X(Q7@G6z0LL^Ltcv z-2DW<=z+NctjydnkOhx6-NbB)d$%(zAf%wge_p3&?6En38U|dQ3xMEFepxSpC@m(1 zXw1IBaQwn3>72{s(9ZyWn{v%u-9!PPldv1AF;E-)bmuH?ZvZm}^>{^>rCrBXnU@27 z&K`uklI23=8eGT7K+(r^J~DTzx`xceSA+C7Z{dfymDXB!O8}s^H3V^Vm6{3RKqDMj606y!Y3ht&HK`Mv7)OjTFK3F0pEO35itnu#3-_jWDIfoSC&Tmtg48jX z?-?fIpFRIuP@$s#bUkKbrz(Rfy?a-o>D+nq>YL{XMt+;(Zbiz$zUQWQPxx>Zuoxc? z7VGLGc{-0cI|2PsrQ8CzM3{(w9IpDXZT-z@NCNqY;0qn}!OYEl?0JFaNs$$2oGu!C z?sS1P2%xaH*8pJ_{(DcCtP%~ddtXb$Z${%eJ$ zOh0(X#?LP~SiR2hvoA7zRR*eE9fuRFPp7O(9M_Bdmi-^s7mKSM z`IMeU*gy9FItaU;m*l?06pBeg_udi*<;S{CYQaxKXc63=0_bCac~LTViWa z9VL{b2+cn9?p1_%%h5^M9OabN=S9sx0MOV0liQalO=9B47EOZO4Q$6O;TP1>{8LI1 zFZ?)6MJ(pSmfX7~hW`vmKWv9>NH&v~oAc`pgNXrgao_F#!xo@J7)K6QW=9U-A__6# zDi=VWE770u7Yv4vmb3kHwvVJ-Za%o%fJkU@4&2TYDqPRnzbFh5 zp8LK-I26*A$@D|q-``%P)OeET|5a?JDnmcG9a9t+_;g7Q+~{%)-p6*#hh72I^j8M*l!^9b`?;ykV65i;@ zMN?B!6sG+$h0}jqZK61&`+-Cgmgc;qG8Zrrqj0Q>d+$<*c#;q#Kg|BJ%CAZkFP9~PVj9iU0VN~?=1?U1Vf%g42~+ksjlI+ z4Dvy!SYv@h%(BX-t-4b1G-IdUpY3d_5Q;UU{DoDOA(^4q@yJw`cEpXJ%~?^@(K~=# zVQB797TMHQ+(VhA0P7HqrBT3RC-dFxLZC68C}~pz&^w+gFlAg2$;nTa31E-{Rzttz zcQ96Hs3$H1FN}vjWvQN~O2n%`f!VdozQ)qQ&79xiV~XqU9|;(MnfJEWy%s~-J*(4; z0rLg0N?bn#;?{=U)hN{*=k@BT`tlT$-v5+f8gPk^WSY^c6d(*B06U<1u`W!6f^*l{s$=VF1t_L=_9N z&;s028x9i(48>U>fAgK8N_75FCN!vWYwRZd6|P-pt2wJmlc%2I*A(C0EpX2q85$U9*X4#CYCM61nx?4QWi=w=aGA-we?>a zNr3?zWm5-TE#UmDl(ob|fP&*lMr&NJkH;pDK9k(J6jP?0b6DI^Cm#jU$L!g%7_huV z;8eh~`l4NmXz4Y&u;|olp~A%q0j(4ZfEs<_xMo`FfN%2BuoJ3yUUbD0;VHN0`l;`$ zqG)zjUOhHylPVpc%I{yIoDn?d%0{_&7 zQEnm|gIFG)nwG0)WDhiW8t18HDW#RW8pdSd|X`xgVp(Mi`yhZ5`?uWh5 zBL2SoA8<1Qs%mB&Sp?j)(EV(g7CoK^bHKVNyJo}Gq4!%BO6Goy8=-!)T%RhsBG8^( zI6vSOm$g<4iGO0ecv7r3hCbr;I0G{>B1vhOwr$RREvxqM^zW~RD*ETtGd6^{6-cTwoeb4`XEGIf@N=Sk|FV+-HgL!;9P+G7J!BeSN9+taoyW zA7I=Ls82AC6&j#dw<(DZZQ$5WLo4Ebx_fLh%lQ6fH!bt`@X}qNWGncFgCv=N9l$hv zkJIOJM_YFLueQKfwF!Ia;~2;FE3_{B9g0BatQUUaMjjB9&3Ovg@Iai-qdBAN-Pnxi zyT~H$uy<=#jj6b;<}pEZ`Oe{xIpjJ`k%RcY%SUwvHf}?-m6kIQELM^A|L1R!sO${b zKSDK-I+(;StcYU|+D@&LqEG-++9>R?m=|ShqRJ@-emI(mE}|Y5T`J|P{VaE)b^xCcR2$$`{R{jeL90@+a9U`zEB&ZRH7CUB?#d$CqS- z$QKL<2gIquUYa_QeQ$*0Y+#>yM>4!rf{J!@6B(O*MIdJgJ14_-Q0?Lbl%_ByN5^ja zvhsMtfM4b!t{N@bKweWHj(QIl&>KWu=tO)XeMnvrFZgvfDERnzQs|&Mg&vJKy2No!VYm+4q)IPH~1Z0*Lpw+4=2rx16o?fT=;j}A{`Jrq4&t8p>`q4p! z@0j`wZhTN4Xc2l-{+b%Mx%ldC)#Lp#m{YsSwz@D9UinPReYlnuL~M{Y?~4PTFZv6{ z_l;I>8NfLQ;-cF(_2wE1SP=9-I~Hd#1vmrPDeNkvJk!jx)l?pQRZ<565yjzFTbzYb zg>=NZ$dIfhMjZmbclwupsZP22_KPD)2_`>m9T+C){$#r8O=*Ay&ew8W)B>5uDxSJs z4kl#(=`|>9F_1qAfn7NX(fr4|cZFY!C^cb!%uH}Qj zR_vis8N%HC@@iJ}?iOUNkCU=^oP3h!PU|i8lrYxyoob<_+GRUHiP8kqOi*5AEB>3G zmt}?ec)>|ScEmHsj$J^(vXL_1Qqae#3*x^r@>ixES7S-XKvvEL=0C>T%274DgDgCE zzpFrTfwVU~OGu34>SNiX`E1CJOy|*?A97LqRm}<=)Spu4DOM#-C+mDP>)!D^9hYt; zpDx*CTKLD&g!?lg^l0)AJecglU)4HaS?W>A0&RV-h!ONGuPJ{y6W;v&nKp4YllmI^ z$f&NRXU&~?xBt^I8aB;Y%)3)TaQKcF{v|3ZH+|@Bs3O86HCAS8%ffp7AG{7fkN!@# zLnkzpR@P}r!!R^*_=FNL@ii2wl|n{;z4y1FOLDi7GN*vQjtl5Y{UGVvXf~bGv&HdSkaXdbOrLA5#vkgMN}$Y%Wcyz;~V;>BuGd`|dW- zoqBL*P_)gsGD2!U9lVQv&xM}oPGgL%wx{agUbt_R{3Ya7Hzq>9Aw#U$+aj5c!x6co z|H4~U(b&e)s?W3Tm}RR?qA7-(9IP99=y`=yfzB{uT>Aref? zxk;H<@G%^7%Aw<}(Us=3jtl%xC zraa(J`Z??Mu-}j1X8zwT^i$7@3*2Kg4e7;$XS;5R3s*;T#=lpNe#c2S>rLD7SvEW+ zx@je;Fv9(F*=7bQLTXgqMxqKAijJ|M{zh<=0Ez7*xdb_Odxn<=GC*o^_tH{?88sVmIQT4D~lyR#vPt~N`3jCP~O-w z-t3;WtDbceiHF?Os|gn{)H55i zDzN5mg~Y+B z*K^)}N5GGYStI9{8fn$aQ98$@rco95@ZGBAciF{iS}nhJfZ*D+)Zq~Q73h*=^Eb;K zvzyKK7>4>vR_MA(NEqR6>w$72WMr@qW=koSXf@e2kh03A8l|kL_*s=XrSO63J4j*Ns~O4 z;bBUFWQa(=A)6uV`Ed5gs3`l*HEDi5T6;Z9vCPLtS!WAlXHavWZ5Ch%9Jgsavob;& zEo#z$8DekQFOd5oRi)E`p;?|CtiM!5@|p^+ogLa;6{h}iz;i_NU{!!Ot@IHCSI(r} z-$4bqa`9ia!J&8`LdTqa@H>nuLB^c`SGoA4u2o2Bdp^n-4)a>`fNjS{+-q`oFx#5? zS(DZZlY@wgsRl;wb{4zqx7TUBRkx}d)kWc-SK5z%Cx%}=G%K$C^BSQzUE9f>~rnc@i3DR=jCD zJt-%c3;s2^A?Tf=U{yp}F^pWv`0AG>@dX9I7Dd8$OuS|~cTNPWi6>lEF-&nTztgt; zA*<-howC^;`5BkZQ!(R(7#Y9Y?&gW!Cq!RGL)DJE7y*w3IQIyOqTs#fXm6se^1KJqA=n7qu5eUwC|L2lV12otSS zy>4~f=6X_6Ta;6Rs{(Yu9h>n034Cws=h-{MSB(=hKW!KF_`vFHw<_7z+C_=XTyi5{+Y6V1FxFvxpCF=4Tzua0Lv8mY zMop04DLG5d9BJTuxGp%_pGk8}9a3iO9$~Lk^=ZB8pX!~iDB<{iulMD>Y&7~sI+g6n z%@zOPg~0+Ut@b&3lWqXziU59G2#Lx9p}jGX*Bv z#_O>d{`g_zw;7EyYArxhMmWrGqt^N?UpPIy5=fuv*goCUu_m6EfWUQYA$EnaHlVWJC=Gx)iUNNJy(fSWs%noK--Qa z!|mJY7apzByfC4JX+f$p_qF#k)^OI3`s(6S9s>7Uh#72|&LFRqlP2Q<1K ziz&&S85N{-zJWGYSBGA~86ZAL2^Vu&Nq(iqfZ$>MNx*$gp{{702Wl-nC&}XGthIN- z));?7D4VfIjuML$Y&1~;eikXgOTgiN(1ol#TSMwV)hcg>^WYboS!*_kk1< z%3@KAVf{IhG4oIxh@`>W(nM>v&{Yj{_~0#|IGfIU{x8XElPvgr0YApyijBII7N(zH z`RCqj0_-<<>vfnev}n7y69kUtH4+5MKyr~cVY5fNGF7cvU5?#WM%Dbe1b*ImVN>vA`LtIXU1~X)fIK`w|el!k{&=?l&w{P6^HZi-S{q50*|I@I%2RxLZ z8fA%bG@$joW%t`Bg<+KNGO?V8Wk$32Bu>x!2kA=9-z#;Hh~WY%Y3_w{tpdA6hD(7h zctyuHZWRq6Z}mez$MSv)vS0I-Te!6}e+qM%&14wi(V`bcR+&|9=72CUOr_8hikbDM zW+sQmHg-G~0c(^ns7t0D1-g zTYUL%X0PqY~{XfU-*g->Y&$dw#9^(}34! z8SUUUc9_k&W=G@r&tgn`pZ4%-*`$h|Xr19bd@}p6NtVzh;@y;@lnvg`{hUoqNxE2l zy?;K&|Gu+(NvibiMrE1*Y_*6Zl08qI0@T%Pyn^+IWO|hf7kbUi-aKkE-OcopNlt^U z{_QMTCkzoSI?66m*;+@OARi9@K?~~)(fbG!&d7r<9hv@)%JHrn_fFapyg|*p@cYB! zU2M*@%6Zxr+~-y3i8YuhZ};k8wNS8p3l0A=qkg^GK|kCw#&Us&H4#GRaa>K zQ?rpi5v<(_J$2cyS+6TSfMaLAtu$qe4s98)s=fc3S|>-FLbPdw;33@TDAa+zY4Cy2 z#;29{<_oxY>Iw$kWyJb|WA`P>!fN?>=Mm?{YOs0)wpK0PR-WIQ{hD6WPtSrdT4L>~ zLO+%?+Ng`}nY*E`GjI#>5h$(IRk;lp7Pvo-z&K-Nm2o2Q53WX{i~)l~pyo-@tj6Onpv~9oP5X@GsD|MAdOTRu7fK6uY)AV< z%eL!Dk?dxB?n#Wcixk$st@dd2@-f%cn(TB^BD$3PQ+xQCUVd`-guIqTlyose<395( ze?V4(5_$pQ0r+`Uhh;I?SB~V1s~IcBynY`sTN?DQIpQvg*YGR`Q_PRtp@tO^hpbJ$ z2HSQBtX_R9Lvfq)w%Hk?fj8z=ys%{UKCcDiIU?(#Hr+SRzsx6fhHQFWr3Z4(_@O!s zp$0W7Gu}(qk+!*qzMuO9UeJ?EPr|vuUY!!Kx9Ic*f}gL1L~I=v!Pp^FZuN=FM)U&r z@P@eypm|^Aaf&IBU9)A?6k5hKs?a(5+cvc|1Z)ubNg7td>4ns zjkO*^R)SZxD<=cS$S$hR@ON5vnJs-rQTk264umhO_3=GYKT|h!!O`(7*EMGsro#6@ z5btvC20nN#irF(CQDC8+Vq{{QXJ*bledbO-%q%sT!b!0zuJjmm*l>6F#l&~Yb$r%~ z!UckHa!yjh;O09mO-6yj{>akTH$ro#pbFBI8 z!QAgP0P+ymYfH%TzP{7tgAg0Ph=2T&CN!ErxAdPbudl(F4NC9|O&316_sJm&zT_h+AuQ@|L zpdLt-vrYb7nkOG~>41Q+L04Aq1=c;hfY2iT=?kyM>y((6LA-lEva;`4JuQeFJw z1H`>|4R6*)jcBFqhKVBDh;W;(Bl1nBrM%P$u|d=34`Z-1=k8}`JNvAvh2`~sdzMF@ zlGkTBGPxTjK*$`U3%RK}MBbQ6slGPxw$b!@0lSmn8RRO(Y(RXiOBokZTNZSH^Ix3F z4G#qN)zQ1X?6nljK?}9<23obBEL2sD%Fsh z9WU=f&avn7Gx(9QUcLqOtL!l&&C$W0vc1?CA8hWQSt(j#+y}L49^@DXWoP-sv?pz5 z`N$v{G{aL<5jkF=y=V%Aa+N-rFr?*$j`fz2^!0!s+dF8kYJ~w{1Jj8&d1x%EK-5*v zsJgj1|NC1GA%B(**M=0|mfQP9gYCjscg=++JHS(m9&RBub`>K8rWISqNN8#r%gChZ zn6o)K&uMN7-b^QUps-?YX7cHHLxW-V)`M$Pun#l&-0E2=ZX&}2%Ilx#%^7cik#h+W zUiESII8vVJ7WQrQ8VjdD$kI8ZK|e*U+Uj4i1h}Q*9~HNEyuH0C6tx!W51k~&cu0pb zOzG}8NTCW}K=q&Fv9EaG=?~`y7mLwR`Qt zWKs?aTjYGb3jGpL8MN;_ShV~A4=O0UEAJ&^t^?_b#`Oyt)Jn=na5T#CHrOjJ{;WHL zw43Nszedb^cOEoi;xlCZK}@s#hA39MCS|(3=`I6_mx(vjBDAN~)qxtvz96y^+m5&c4$<6apUm=QRf^h_LXRChMUY2p#+FhF-M!{#Bk)Sy*FOa zwv6>AS&kqRf-U}8(}RZ&S1gz*yTTG~0ZbHB)`#a^T>bCV>hU_7k9EWqW&3VX+LC(6rv-StWlX2%8!>Lq52 zcxS&}+kynJ&CLc+K4Py60evX$$f_#OO*W1maN*|KzI)qYlw$7b!OcXbML(IJYax`c znKP>EUIvH0H(RqP0q~ z)dD^L=FD$&szMUSH$TjAMyUj#ISxJ;#s&`({WWUeh7nq{=D8z*pVvEWvp(^*xQy38 zTDYm?J~yA|vHjQjna=Gd%ZI1Ev;M6}jZOM_=RZoJr-doM6WgO7b>nVsG7oW(G#aX| zx4nT1kJEO8poZW1gNXicz7U6zx?Ewy*-1_Yp@3u4X|&V*5maE(yeiX9TA#BJ4xBWT zl1p_SKW&>QLAO=7Y4oh4c(<99^t#|)M_E8YX0yN{Gscb2XF`+d>4>XxB;^otl6S@` zYa_)%lei6WHG^z6_j>?Et0{km(f3oi-#O(dV^3Wg$GT4uxF8(ZSqob1TRN*>9F#+f z2Xfl->LRR96W(&hnFjb?Y*hU%_(_l&N>WCtqGavP+v<+@y3&u-_9W1 z0KpkG>VRi?l9UfEfw+-bwa8_()e3O|K-EBn3Wy-6b98Unaw;5_CPQEY3xZvC!zi8a zub4|$G%0=-RlX&zGY~aM$yn97s~6MZK9evY7}SUbY7&0sFR&1S#*y4$<6boZ3_g} z2ttZmDaJ_Hnx1n*1%OXIhsjwSBz5Yk-x$Fo0htJc`BiM^NRJuL&YhF4;1gKqmcYW@ z(`}jdEEW`k-&HKuZY$~l{*iM~3p=$tdGO8cJl0&x8H}=)ehUcGs1}>Bo<&ZWQ>64a zXdvZv*Y??opk-#IM~!Wm5z$?z7+jC`+Ao=@Hq| z41y|f$K<2225d+4nY4dabBo!DFC;!Z7|X=OEm(bm;qhoO>DhR{y78x-_hT!klr#xW zPi_%Z8$&E9@>a^B%w5zW7DH_y7XmT$PuSbY)k&2&7Q_q!I7*fXDh81)<6wz$w?4&FlnG!e!?dV zBEns9y_^+vj#Y$@uCTHB)y_~0GOw5HfVMLqEq@1Ac*VHyL%7jc=>A=IN@M8WQL`uA zSz-SFF=7>4)esxCr-csp`yCDkJn?~fRARRiSC5+}ciW`5_kkzI)>Oy-1k-tefG|8Ymtn@0`WJj{7`XB`Z;k^8HSMk8PK zYY=`$jmN9e0P_n#_R+soW&W#V`8JPQSfM;wPPujFU7i)C!Yp6_-A`Orh`fP{Uwj-r zeo1f*?_d5d?}}*Y-E4O85iJ|Nh@3JyIYxNW*yPxhx$imA-Tb4bpZEh2or=oMhe3cb zh%Sr%DE@%HQsvHQ9ji6_*CH{VOgrw=cL<^LQny3B5xY8z^|NJ zK@Arw2z8v7XyUC{UWbp*2YqXEn3dtYF>l2l<4vA&Q|V=#OHRCi(#uD0{7+5gtcUu2 z=YS9*sL9%wk9l9>w8IE1;m8N+PP!GN0oP!|d`rHmY~tmrCtr0SeNDxqc^^o^QiT^~ z27Iuq!8#?rVwln|*jQNMYN-)^CZi|rAY>!b98BSfZ2VM==FvlPJB_oM-)&sy6D^F; zWJ3${lQ$jb{|=Lts}2trE^&_SvGXqTEvr4mLK|UKFc81WK8ksH%`1k=DmtnCR7V`l z_G_n=IyM9j$p}KaA zvz1Z7p9d{&fyeDK9@~C5SI>H{_$O;@*k}H;?N%oSj$>#XTRT&ziwVO^9^{mrcrk

h~*trS(YHd}=QXqK)fzX$@$aH2`AQ^G9BVNvjwIcL&8LV?b z128-LNH@W-mqcCFw}hFTLJLu<7;i5qww#Pu1Zpjp_ zE&fOEf~P4LFnm*?ABm!dp->ePM-SyWr_DojuW_O`AVvNp{G%W!33W(0cleY9#qeEr50 zS9MfyU5$61QKf%rEQK1|12hwS$kVon_99iR5N~6a)H{{#>l9TFye zIvz_SUR&LqkYI!ep|tMyToe~&f#NJ$pm+LnJ$QzTL}pq!j+P3m)!=*k@FI4vQgId5 zL9#8dLO^8aW4Ix_VV~B<7fYm@LKW$teQ;_s9@8WlnE(AuSywsmxL^KVge*HYmYlUW z#B{90(aSy!ZJEMjZIk)iYk&+9(bX+djTb0X2L#n$Wk{^E_N+$6DiXmSVIv$hGzp^I z;&p5ZO>=F2O1X;1CYjTeKu+J@g{tVyt%^CR$x5RD&9k5%N1}ue@d0xqW__)<#>}OM zWC?YOj++;_J?8E!+aS;Y%1Y>n2x;4?Iwl0ucnz(GAbt9BYqagZ$% zggkQ5%yPD;*`$cpNz95LNUyHubFH>^bpDMPKK+Yqt{qh_^$*~HQ6Z!^ESWX3`MO@g zXjxsI>z(+%#b@O04v46yo+N}Jvy8o~A^Jip@C+Isi%WhB&Cg{!VD2!+$dyO;!!5u_ zSON9z6MQPb#w(ZhvZw<&qbJE`Wf3c|c8n|0SS|L&I5xCL zzp|_|kqmpAXPUYkIA#ap2!BMzGsx242;U%*=tA5_AZEm}LLp_O?MEZeSkSbjtwZbLtTYYY!?gBTrZ0I{L1p`Y?3sG23=R2VlDXOG>?bn>|g}4qRKB$$vlza4O?8J3}St z{WMh=(CcRMb*+{|s%OeZyRy=8d-W}(pZ?mC6LwPGC;bi+QrUizASdiE|9K}xGC!fe z^CMo4P3Ju|GigPm`q6d#-`U#)Q?!0f^j)<22QjB1uptIrL{mmxE17(54_JFg7`O1T z>x&+_4;JoH1~E{uePkiX`�TaaBWV*Y~=y`n~rKlH0SL=xDDm?g6PEc-Ht`%6xKYJV!V)~MeDEB{O!yyAA?HV?~L9d5*zyXT<3|YDS(&DbD z*U>S|A){iUImJ;9w_W5#K$+&=@O&}1<+#5=oz8BZU*rOF@im4oW1}nOTzmFOYCN|9 z`k2lscj;P7iMm(Hcbjr z)PPk_w6Q`dZ&R2Cp_mX89mD0`l@j{<@3z)#f6%Z-akB1}(c23CJu}EM;czYc!J!($ zWkYTf5kWkau0#$FDI{Ld9Qsu_1niqQ2>BUDhobo>+#ZGmqWj(xo~@ zDE9voWdTq-*`72>%Oa02YYFIsAf3#KlVHq7O7-3P4!--qBJWB^W=2iCOzF%}Q1{9( zi#zk6tWbMW(I-6*(QLA5`M5x(Fb}Q)J|PYgTBCgT494Y|atE1Tz~m`E36UFudkU2W z6EjnjoW9;~dQ<1~8!kw1!DBlX$gkcYtYnniYVHZ#_JI1(a|3NpwGLm1jnxA4rbb;) zkV@p)5gQG*mzevmCtcXy-bVW-besjY9A94X2Auzpm3BJ>qkg%=eEYH|RMX(N*}kk` z2AJS1dKnu^eL!y-l*rx?P@7FWHOE$!YTz`pdv7Qwljhtqj1s~rBOz@3h_YqJ$`kCG zubR`e0ozm(5Bn)P)4@^GEM;R~wn?@L@E&O%3{gWhC5PtvQ+P!jE!Ja7uLz>!^1gjlat%le8 z4{qKBHFbGzc9qB%3AJf*zDFxf&)>#?wTdy-03M3J<5Uv<@veK9?-!!wspDl$1?Cy= zBtimWjX2@_=H%G<{pH%1w@3A%2G1Ym@$fGm*S+|9-g-h9I8%Y4;jAD3Bm=`|H@CS z85W&FRYs2!*DyYFgPn>_b#SB|_WH4-`Is<@{HF3XSTkTlT*=&9yK2fh++gEFKMB&p z_vlr~k2g)Y+L+e}|GkUfCpm5J9|M}7C3!*2bNDs9HWo!L=@`rJM}G*V?Sb)PUXiP< z`gH4?`Vyii3e`~>z;Q}4uM83%WByxH& zOhcg>%+d0BRG0M!7gS>Y)-e0go;aZTj*MN}s9ionJDjO5Uhamai_^-qga-)hKiT~~ z@^eUkR^FHO@Ii@y{b4yN8{bJaopUvqSZ2`e)$>mfhYwG2-l zls)44Q~+on+UsNd=ttGgUt{-bdOKjLxBk(KY51{AktFdBvrRk%dKd8qeap+Zl_xzh z9B=zOU6PB_0(k_TuUp@~tR3Bb8YXtQRD}Xp|K(q5_vyeni; zbbG+mbt_cL+6{hgNR4fc?)HbRd$UuA| zUAAMtqs%Doz8OItaD_UDl*D&K&sQfacoT?g6vtPJ)H&O!PP(8W4JOG`aY=#aeA5Tq zo38JJt5Dmz0c;KN2`X(ymR88;NU0kQmZ1e!ZoGz4Yzt=#Eo3Vm%vO(bcR+pA1zNxg z0;m0Ih~Bakj=oM2q~~cnMWh8?k~StH@V(aOENtla?3A%p+-`*-x4-U)%q)!KI0RThFB!Lv5VffSOsv?4(t<93_@BkOnX&UPl+8YZzOuh|9e@4M2ZhqckSn(KULda1p)fMZtLLLgee-SCXWqTU@OooyblUCk#1gnSJ`Z^$x&(RhW@|q2|#A zBi^nl;xv2|tO}ol9Hw?%pT`X5ldwm0)dBAUYqz_r}^0FiUMX#Y&5A)Dhrk@nlyHBbU) zSHiHD^noOlXFpE@i$kmQdAh)ip~|8D=Gd&tovD5xt`7kL$|xKsWLW+T=~l_tuS>qf zzX8{yB;DJ>5T@$)Cx$rD@@-hmCOl>qD{Zy#-zlv%%m6{DD$k(wNg$W(FE!6k;CZrz zLF`4-w$XSLC{xCb_c|7f;f57ZQI;sB3tl;cs-gJtdGtK!{Ev{Z^)2wPf2sYp`A?cE z7xGsP`dcjLUDmi9*R5^+(YD>4+KVesYOpr--t%ks^o<#l_0c^_?1%26dV*>0hT_3Q zLwr=_#N)36T4-E48B4zYjGlSRdD6~}kbkb}!My8^z3TmA{zyaq58MpPNg---z3zGP zIcaUsB_qRuWva3nVU_gcjZy?RUaCL-tzuJM;&0IoGyD#S_>*;D3f66*p`gBY=rMie zH@D{tTckLadf?d`o_csYRb6Hui-k89g_xT_Eqf2eC8N2CfPhMJt zj?8@rFHY?w;m$!&ts7m*?(g>yyvs1hpbTQ25oc!}P`QQ1r&!Ep*njKEP1oLUrcsyQ z)YR9GNooo4FMx~OxkVaE+w?w_L2SmwHqRjap zXQ?kh2Zr6Rn&vDC>bp$Sq6EP)NeB1(F~W49wE*v=e%tX95*7CN!^(l@C~y0XZP^u9 zbTIT_nndTZ&iu0CMQ`hCgSB0e1_hCN(YC+IOPsV+U%dgH>%q<&1($Sf-d=#cU62ovf695ju7fQ@u|-L@)wJ{72_KBICM z!bXR1UQkzS`60mdiRbvM-uV4Qi^0W5=-_KZ4Tzfgn`79fXlXuOrG0#8W^1Aausq7t zLu(>w>ihh_U4G=590@*Ek9r5f-u&60j~+kM!+HYVJl|*ubu+z5Rn&+jo5U8il(|$= zA8W!f6c-CK5*HVTcc_6|3u#Du9hfGhcv zd2+t;gyimvqG4&IgV)szoN@F++Tf{u-1^>V8#e(3f;@D9(;u}}|GHGpQ? z1=3gGaskQRza#&6UnCd+qj$swogW`>bf|c4d^}{sI4mc4SWF&)a?-a7-3I5Duh`x$ zukqKr2j>Pc-}t9pxJ~*C$c_X8E7pDSl8eu2q`bD7HWnjS6P^HV`wtPZn!e2-&8^Yt zF?iZNRW;Uh7WDSdHPLFbdLvVs3b{xn)7tFAklRJ*bCs!UekNBpr*!_6SMrY-_O|UM zjcjgAw9W@-)S9l1-u&!4t#!V)j#YBE^WMcT*|b|LMRLx_+gXYV)PQpDtLIJgh$q^8 z%=B{L!9M7j%1_{=O&~ba}siatCITIuC$yX z$WsF56X~6O34AZptCys#`Gni#u&w^do^SL5yDlzN&W^Yp;lFUAI1zpxQRM_6yhqNR z|8jk0JGw`c6(?7gC0J(#SR?LEdO?(lr|h}O$wM+eI_&V1v#+`us#oq@J%F$D@Hf&_ z4ip#w!`&d$^1XB;@adHK4C2`OrU}?-sP4o2B}!bLy}P z>vnzk^0grdkDx;ogLYc4rFyo|UYpKQ+(?NW_0T;V9swUS;3vny+%ZYE&jmS)Ur?*A zS1VVutlII3wS#?wBR|FC-K4Df4|=>8SSqe2QP(4wxtF3YgM${qSWhjfQ$BOHAP%paGQG4)aL^~VKgy)ArZzPC_2iBLL*K1l=aJ( z%d!^KdHKFTgFEKdvTQmFqaS+>Li$)^yu|SBw+%IaACp48IHUd!enaEz>1d7Ekw_Wr zgQ)(Wj&G%;KTFGg>}ZqaQNi3)W1k3+Bygbt@R1AYnF6NHZly^b{BNY*J6HkL8An>J zhWZZ0FFZ7^t{RSiNt-mA$!UWgj3kRlMtD7B7zT+N+}qNLBPjAety*A$uP%R>1ov7cDsCz>BCIkhRfMpmTK1z`W^o>;$%!hbj8;i|uA^ zrki8(4qmYCcA;=yZ2coVpNT#EDiS{W~-W&In`86&TetYaohz_5DEfYiH7%Q zC$do>k#ildiA$UphVCN5IQ!)qxjbnAiB)*(St)@3Q=KA1r?m~yf-kI`eAQRdavCT=6yAw(*PJ+bu^e*`%Lf?B+*?CMRn5s# z7;?xAu1A*VjWx3^edu0&jd5ew3gyA?Zlk8U)Gum^Vo#ix{qdwJkouo$6^S|(ggk}% zFRQ4kU*N^F8O$I7&+M^hz$HSEhzWQ?Dr4&fSlhT#E32*CMcJ+USVC?t-h{y3)=R&| zF-$21i6=j)Rf&LR-!w5%S8w43FWCo_1g4tq57N`>&Oi6)u;ey+5J+`89WO8JX$M>YQKFe9gg+UGQJMk_$=}ec?~Tj zgc)E1H)v*P?bcX;Yt@GiDA$Qn|3J#41O~tY22&V;NDCNwA!Qx!xWuKEJDFCVRvD_P|rxE zy9v65xE>>xvy(9~!vToc2=(RT)Ywl?=>bW6cWv?;J&fZ-&5=DF49+k;E*(aYERlAe zxzel(Z8u42F1!YJ%5QdsM8Qpa2EXI~v6XN^2 zevtX|(A;w-1j}vH29frl?Ic$8;TpHr(I?R8xBWy?4L)@!{&Y^cySog$cgm_#LpS%q zh58=%|4W{=z>Bv>*)Ku|N=JNid)8h5uuoIMb^@pKX%yy1Ma4d2l)MF@DR5AtF)Ajh zfwHU|&bER$zZg6_aN!uEr<3TQ)a*{c=gkkfvMAQ?P)E*M|y74wWRD z?K>upD%m7lz`q7}t7GZIeZSB@ex?h8-VPmyo4JX5Av45SfjWevqgH>w7Xc63VTIVE z>Rq`^z0XPN;P#wanSo^{IQgBK(;8WXIQN`taAoY@@cys^|#S@@cw5U%Ugx;kI()AIdRJCF}PoD zkXpLj0-XGgi{XdfBQiD?6>b{sT>j9x^AiOHPN&~~jA5MqjOS^ER`XSjf96}KUuq!S z<8ygxU%c;B`jesLUzsh)FRsrCGYh_dIt&L^v`Sb?S3Evil~<^vTuiB#Q&HsjUZ zHz!^y=umrl%J{xn(c=O!+M)KqQFeg|S}jNL!9@{%O0b(#hb4dxJ(M!W2^x7rfb|y4 z*P8lDP6bx=Q}%Fs zbo+ZRD)Ve9w(I#uq(v0DiZpcfH&QX>922+0i2AO>2ll#o#V~D%p1=WRf7SZ0WULuC zy}J40BlsM3-N&tSxQ4aZAF%Ws+&rtCJ-t8gul;1Bl0_tKKM`(dt-BxY=tNYrcpvz} z(oi^y-%z9tOxaAEhKf{D_Pf@R#=WKUtwz`-xsxr#Vd!LEfrr=7Ykhm>!=ev6EUgSz zyAAO1h(f`Hx&9&}9ae(UodTyZBwq0B%?f!(Gt==@`EEYC;O)^ane`>qW?z8>Z9l9S zt(d~*H*4A+aFsYSQpm2P87y?NszHZA){zaz?~5yk6{v1Mm6|J$nr#_aXZM4{-RyeGBlIIqdWnkB zt2Fb0f^pO6kK?M*6!dE~n_wLM>s_x^XD&qejyjL72cUdg?stW=lN;;C3QXdcG^NtX z--wQw#O-cSd{6s5>%RI*BHP4z5Tk{r3|__$ZvCU5$aEkl^UnETVb^~ zZZvaCt}(%p_ebzc*>n@Bdv*pGu7Cl`s_rf&bDHMw8Vx07Qqe)g52*f~{W>_z=&bkw zHGBjL3Nt{hFjtS21V}OLVfR$}^j&^a&*X8nPn`TF-*bxn4M5>~RVwn{Voor-CO6qx z7;2&=UykoYT*NMS*&@f6R9F0x*zq*S4$(9;d{|%q=;4%YGyO_jX)iLwAX9OdF})c6 z<{re><|)^7;uZSAT;pB2N78ENs=ch~1}*9rPFZK{O0=PFF+1c3(&w{L6kQd_wVEv{ z9u!Ku3+JeVSe;bm&b+u4fy=}jPS&}^n|1B7Rg0(b56w%)5UCw!7bcu5(1bkw+__kV zGEohcbn|hHdVliUwP|e5JYd#pUDn6s;_M})27=3m<`w%(?O@^Q>Z>PMEFaVJ zuweoFjr|S6{^EIFNIbSJRQ%5Vmqf{wKRO>{hd4X$R~Dyxk5)MgqgC@61Tlc`(gvjI z1x&B`VPRix!%VN`<&XH!k7MK-$H$|&l0k*hQ-tcj4DsH2y)#{|P;nQJYP&1NQbAug+HHSgd)!vvq~ zU}uL;2v!fZM|N}vwN#}>=b}5gwt5d%A*)ko-Igc@LN!9$C9Fz8#>Mcqr97X8YNr;K z4~Gb_P9Ij4wPCB&!ZleJwbXCK>ArtF+cW>gA#^~xBl~K56l`9L`=^0DYZuV{eh>Y# zYyJmbNX0J{M9Gq5>|~MP*^T2QewuMGUaf{8^SSZbH)f_WN>neimQ~d5-gD}jxdz1` zi$KF_;Y-#j=z0f_1(VX@Kh;36;%h##vpfabQsb`(HICtbEq|(FIB2wN7C$7BOe-B1 zHUX{^N{<%luolXDFJO#X${N9%TAj5y^vtg=dcIgM74h<3-*9K;ZZ|1ijWJOmOX0zm zsGfs19mlz4WW>W!kuz29ZH$b6YD{{-%ci-SD}x_f>i4)}@d(F#X6*}EL+LgEfBV@` zRY_cbZ+I8+q$w}D&ysP1x9ejV@wr6tADM)FEuAjo z>Vt9O((1+AJO)>)D@PWpYY>Y|o*7jq-o)JI*2Q+d`c?IFxwZK1rltq;bk~Cg3<93F zc}wD7YNsv}SoKTiYZvrisp#(PBVOQOEly8@+Sf#Rf60kJ&!jtZjNuXpihaykFhN%< zHJ#v3u}bj~i3rX>5vxoeQoFO7zX;vvfaYs*_f#1)xlw$F==s-_gu&mw?XrC1`w@GWm*~=M$qk}!(Y$nenXi)g4 z;^cRzMsei3bR)j`mo$S`O`}o|lX2)fN#++a?XTDS1LkJ`q#{@ZOe` z*_1>zb(XAtZT)UifOo>LiGV!3YL;o-NYV5fZu!f;MM{NMzp0}axgp|B00hxthAd)3 z9_HP1Rl5WW`w{DKuE6v1mlJ)TEfrZ8_&ZNf8Fc$gKeBuV<(?wlAnTyp<(x=M1G;__ zBXa$q8xTN@*m@xL3La|-69L$ebJo5DexW~2GhGc|Ib41%hWs=23g$f(4y5M(^t+oO zFw-Gz#Y__vz7?v5nmRmGHE;wsTEX?zs}U<%Uzn>Qd)|?ky^&C+FAz z40I?D!K{xS_1t{^e8y+I1MXr8=bGfD(y38UacQ~-@2=|R?!jhL85PFD)uOr@6;;i% zt?NDKYeM6!4jXUAql(g*BDvyO1-MrMI6@h9(NR5M+cvEG>CqneP?ABU)$UNlC7CiX!%@&2+tUD z6ciY$S)7?Kr z3?fC1V`dWWo| zN24c}6+dE>)}~J`8`mlihO5|4&t8^FfI!%q(iANN zh0S{@K5@VK;9pAdsry3ld7KE`(WdtBKfvN8k5R;Ozxr%Iujz&k?({%gUDeBMEEM&| z`BXbI<2{tA_NzOH%WK!wu_7_^gu<(Z6!5wl}Ot4cehkQu2%isBb^EdEq0 z(t(u!X>e%&0Fx8k<&ngh2lU{FdPEtedl*P^L3)9m{P2SRK1t95H*3@~^9-k-a7~eH zGMaDNz&x8(p%UpCx{(%G)d-M^`n;-ndDO8Xj_n7eww}wrZi_+&_nY{H*xVbduScu> z!%i)lCN8O;!;S>NlwyNK;2x8_+=>*kk@QOJ9T*zsSc}hgkoR%mhO_OQ5-iys-$RUE)zrNJ<4Ov9>$MpMB zBN98_O&mFG^PoRG{Zsv?WWzuTeg57>xYZd6Zswfnvbjz~p7(C_R!LLh!r9Tcr%N`Q%WQ3Q(2&d*mlohq-oT21Y~Ei;f+to;J{hrN;#&?kLtsD zHcJ?0I+^q3BmLx#hQYS6J-Umbv{hHbwy9`fl6B-ZT6s;&GWNVSG&T%|1kjqs!7hrg z^{5Q8^$M5IO{rz-51*MY@9_Kvp09+PvNmE<9eAPOkg6e=`oz-YlL$4$78sv2fARD` z*0ncFAfVx9+YK!NPC);c9jP0bSHKDAs8C_9Vc4d5NDVWNckpsm53zO~=*q~}?f(Ba zaq=EXUu+CwzG~55own2@hl^Z22&>sngvrFs7`R9dVKk@A7&Jn4f^(vu8I|X4qh>ur zfI>8IZc<+=$fqv_x8I&xu(1exjU}6J_P?7aFM1W zQ#_Y?&Mc0dXZ-#0L~@!|q##XclCR?(fQ}XtHg#rN>Qp9p_s34t%X$CDpZVHZ6l$CSp^!f29#Udh7Pa zK&we?q96v^I6mD$ss!X$P&?u`sKttd^`$$Bw=nkEkRAzg>&~oe3nm&mE6_YC-3e|w znmri~%4qg9bU5HQo}b4bVjV*KB+bL)#dZtxF*|SICvo5rgP>ZEUHy0x|3utY_gAv$ zCVjvfdJ_+V#P;4TbW~}i<5HN{#?4`V!k)>kUdiJptNI|;(*LWSayN9e9J(A*ldN9% zFwrGFoHPTotRdA{xiwpQXm%ZY^s6db=x|7=-qCS01vZ0=LbuaP^YE1JRDOGs|4Oxujl1aQdOD3(F63(aeQz`q|K* z%^__oYFo186H>3$<|P6te$ zVJr6KUg7d+Y1g);Y?aU7!LbW#LldT5=r;(n!%*tpikG3)EaH+0HXvy|d8J z#XHEYE44kHPi=()@97xHTl zNNB7B-*{PH_Q?Q|?m-Sn%zW4+vpl*13SaieEQXR7g&yKB?aUtJJtv*+eI&IUhXAxL zsQfPLvewO6bvw%wPjsn>GBMzFgGGv?00W_qAuZh#o=6^Lq zwVlYi?7q!H(dBVVOp<@XZZGkgB{s~Lb%y$A7om-VGR$cO4J)!=+(O36bb$M}%{?H# zEdi_Z7d_W^S{)bLN|nZl(No&@S-e-XRHGrC%8x#3tMTYBr>_z^x-*7)F=}KgrJVV!?WkUe-Z%3rW+Wd4lj^TtZ25e_ypZDr9noL%pWMxi$)ULpC ztFE@u{Eov8W!CM=!Y_9v%i24oboYo)_Qu<0oKm=v9eTo_6Z(Nwkk09v9a7py{Cbly z3JS6p4c12ls0=CmCG6E+KixzW2rV}!C?h-#!o%mF6z7*yMLpVDPIwurfpHfMtXv!7 z1l$|uhNA6PudVh097NDyG z!38D+Oyezy{}ybA<+k41c_zyp0#e(vxq1D8t!5bL#-plytiL(L?1`gUaV181N+)(EB_JcupGfw^@sQ{S7eYpT9&9jq?43 zsYluMPm9NUqM6*+csh#rSo_MkY}GLqzBh9C5%8YjF6{p20{%Y9x;cLhn>!Ds1Y#cJ z{iD<9?{myH^UR?2RnZ;#^S(LjG(`W1;r?R8TZVEvOi}35QIZBQ_Z4BUURpYDjqRVr znwtom^O%^OzQ!6Pmrm#6Mvm@^1WZ+O7P}iddogbqLveifKWg~-j)`}r_z!w-7sxt8Ct zvu$FJp6)s8zh~$9sNzK3;l1Xhcz-GGpgYFjhJ@zE$3>{@lHT5!% zBK)$FNQb4Gp87}|HH1kWlv|J7^N35Zo-6W6*ci!>s+tzcTEh+`-jcm}ilG1+I!b$L zPn~-U?R4o(&hBvO+(>L`_h5vTC`hQHbnC{@ir}+WaDWu3p0hRq3^2x{+S5vy(c_F zG$t0Nv-MeCX^Oil7Ef(UV-PzzFaBv+=12gg4JbeAK=m^>$P7CnJ{S7<`g%jTAXQe|vIuIsdZ~|!CXEJB1lx_KlS-;0nhEViXVApDTwA=%48gEw82yG5`G0V2; zo<2k@rYo)=RDgg0LA`jm7ztDkNpW_?Z;g)ca@xLesgH*(Kj)6lykZQ4D1EIG-X5+8 zVGpA#{tT}OeU>v!awW9*Kkjv!af8yz{$BNGMQS4}4KIR{#b?==*aM!hsg9SPj$E*z z&m(*0#aYB?sV<-toDyu>A(;_x+>=H2S6u-u?2w=#iFrhBn2}%kZ%!RpicX0u8Oylz z6vyKxBLjUFM3so5zGHZZth$zOL+DHiWl#Mz_3(FmI8jWZ0|7paf%ouPqghNTFH$2?KlQ>vexMt61aO_{GhvjO+Gi^0|*%4{Aa zzMJ5r1&&Qf#_Xg!c=CJ>2~95^EXneS@@m;8Uwnz2*o(bhUw5Z25eeS96T)Ujfc z%C_A*r1h}03{}{1WBS6NyhcNdpslOX0Mc-B>>b*KYccl>fTu(^kkvL~i?3HyDfVkF z+zYegPv?r3u&cGq*xsIg{}@nzUzM11uvZcqD)%?&=Q&9J4Bz}7-pF6|XqRy`PkdkY zk;1EZzvj)}04M5oRKi7Y&E?iID`UZ%h|=uV#R1#K%w|!D)Bj&pU0iDjJT3)vlCbfo z|NF5V^b-rR;L!`#Bumd=Q9^X16A5x3(uAzAM(+woSAQY5zx@V+cL%L#rYxemMiZh=4KD&bxIPH2KkcS z6KeMp?#Tt9+2-2eOdYs9@0u6mr-<;CMk)lH>W{T>fkP+0C&a2oT?}+>-$N?iAhlCx zw_#eY|2QvLSY_Y*J}yCF1YLyK`VecM?F-FbZ28;ZdXjY zq^9&va=%KIpUoQGR|TnI+s43N>uJl*T&_&bvsx+k{^UCYt41R7Sp>S6Yw()kQTw zAs}OtA(n^#M}&Y88!OIg4OpbQb%h6M7x8rbM%54;TCd|Br|XmrJMnR9v`P~8QMmd= z)|P_rtZ@N!p8jmuMLe)s1>Q{bGMGPKs1$g3pDS2_Zo;GpQLVN)sa>H2rRK=H?NaK@@!yT>^q5K? z|HaDS;wC4}bDlNoi++ex?ep{&W`@9z;+j*ZHU3^+Ey=9qBEDNb zTzw40ie$#?Qzd|!4^NM|#Z}o~Fvx2_M^brKyQ6r$ygbN71w$!AFxSi*>``^=ZV(9V zvutf6HV>pxUXaA}A`z@bt2S_xKmkU7huY(Qf3 z{ZmPuR5Tf7l?$*Zd|Qk7w)d9oi$`9o+jvf>+LwGjZS%KJEV*3{%~t4jqW^&QE^G_h zIy92Y6q;!n%|6C>m9RfOV}rWp=0A01z1RP z@8QJe>!*4{b%y1))t)c_HipFS_O9mysu=_C7%s#zTG@X>mk|n*^;owa_TE|Tz{f*a zUL3TQMCnm~(Lye4w>RP>6GL0AEz=U zpjK@vwV2`(-Ga#kxx=R&7MdEFyQanDy+D)ys-{j#2dWj6#CG%X6r^@ai)>$qR@EL> z6#w-|9Z*n)J=c$@O5gYaT(JCm8ubg&-`dH9{$=S6$>*0!$8maAzWvgBr}-=VMWRjl3}^>Sm|nBQ*MeGW~AtUI5)1{HVyZm$g~^S zF!rtwMf&p_4%(U00`vX^QGg@4^1sd~Nho}UO>c2Epbi8Q!W`Z=c_xHY2g!lYoXX!v#Vd z{A|~P%@|Ok$ihq)e`R@FmACjub(bNj4+n^g?YJl`N&o z_B&3NYQDGnpk&TtEIkour2d#5@9^2fAVANJO|ELsgH(nW7A{;GFQOub^H$r5GLp!Z z&@B34Ny_-9b+_2HCDhMpcfXDX&&h}sXs4Fe?pH@A+k=tMJtzPQ92Wj}?`E$MX_-)+ zU=Z;s7C|UI2KMe1b#GoLe6SntF}@}Ar<27TT8+7=yj(4Guq}GHT_$BYY+#x41Y>co`Vs_C3ImZ$JHwgKZJ!yu#nL9)k!z>U9QA#=-RFYMK&R0oi^#wQv zn^$VQinP5YLx{G3hFBp6?JTN?`vB`>N9~Fy!Y79PRAYryy|#d06T2{> zM)m=Kmy*Y58mXCJ=8^o5uD0WqwAYvf0&6%OMM?1q%6}0a#NQi@cp6V>a6OpRO`z{) zlxpDTJXEGzfK^zydpK<`9P=WtKp`v81H0V$L!HPU3iH9Z42Becg-I~mU z7X73=$^i35(%x(CJc8sgC~xCCKr8vQc;@NVi2={&K$@h|?FpD2_HUY1(p-H0#dh&8 zL-P4`wA$+yN;RDD9?|W)L_b|%phcQ6_6S-S06KXDo!}uK3GAWgOWMLu__3-m7(mi7 zQwO?UD&n^Lt!fyMT#`}K8q^^e8U9)bih93_9YeyTN^PLFP zzc?{*;1aWORC$+x-}hu;9$8#{KY~@4?WQ!5Up}r*9>!KY==_=f%2(Np&B)cwysaYadL%|$hV9;Gb=nWS zdQ7i6wBscZt>glQMkvbU|E;`XI^QnIt!(FZVu_9GBekc5rW3SgdYRNy)fgJd1#-2@ z)MzO%6KWLO=oV|-W)3d!%nsUnUHvH}a(N0_rj{_ zPr93UJ3Gxn|M-|L3AWpHYOhf03Gds)_eME2*!eJaMu2vu*Hc=1n-LWdS{6LyOH+4~-*zI@KuU0ji8P3kA>3e&fU%@ZqcQ>F`AMSow5_5`kY$rzg=atxmB?tIE4 zD;@H};Zmz)pK8sS5>>v{>~>=+PIs7`4YCPwJS$)JK1uf=YTz86BGK|ud=)?a(a@o> zYXx*e`Es|S*!Zrt$@k{|V9=U_u@1*E5y2_`Lav=(%XzAVF${KzuV4+djN*T;pOFPT z0{mqf0|e}`B5!NolGCAq>gV#9FX=9iA`EsIB`cI|rTI!~QseyT zbooSL!01uLBjKF(1CNqsw1Dpnxb(7!3$0p94c{`#S{>Zi>R~XLBqrm^pe98%$%EBgBmq$G1PyysbeURD zRm9uDr{0%Vai(xz8prTeuCUe zo!TAPa|65hue0$S&YBbU9eMpi4dyC4B}NT#U#FuTkU5;6lq<}4^;)IFNZrI25hLTq ze{Y^$jeVJR6IVZQM-R1BSRZb9o^K3~J9ey}IOCu)k=j>^wRx{Y%mI{}TeG!eIH_@vp&78Jsfn-Y!DO3=z2OmvC%}`UhMTFzXTXjal{A z-D@GpP0IM!- z%2*VLYZ2abD0zs&uM(HH1=2HRJAMdUoEupb-tYFDf1}#<q<>L3 zJ8}dfX==(h$$=qEQdixQE5FRq@7t-g^g5X`vbp4w=evk+MuEm}^Eh$9CCxq;Oc}FO zas@0kAQ-${&G2`AN|BgK?;46C+ZZ4pqrcmz#98(dF~LkUDjNz(n_rNCN8B&s& zVTB0;Bpd~$g1z>mckW2m>*&voHLRBSWgPo75vIGrKeJns&r52Vb5zHdD65WPPlWHZ z>sI(8ftA>g+i^*D`L%zl43PPrT6HWD*|j$KQ`DmoY@880LxS*wgJ8TV_OHrX;A75* zk=Sx@S{VM(DDogdabB$43;hBjQp8cpkwBj>Mr#b%f$$xr_lc;%I8T8q^ki#5dXG}{ zsow&wyE*eDXE3Syc^iv?bs(BBF(s@RS7kof1GYWok^A&%i!d;S_7!mQ1w>;DM-mQg zw?%pFG`E0nDxoWEFk=elOT@(PS5`e+foibvu-ZZl($EA$(v zWuJAf=navq!PHhmI(&Z4QT(c>TZpK>*wNFQcW_q%anhS}gtFzZ?=-X$^@m-=CASz` z&P#3iA8DWdbB8gY0!z;c4^<1Y@Cg*k%od4LLb{rkZK2pvCxYC{YkL2DNY-fmzgrsC z2JFyPoKPTldjKoz&yY)i_n|wAE=go6O)fkd2&=BoRe7i&%dSCs7j0e$jrFy_Wh%knFmAOLrrG+AM}&c6al{Z!_77KJLHSYE57iZ| zidSEwt2S&Apb^b^Jl-9*eZ&ZbOk)OW}qOK;bgU!uD8Dw{o7blnB=JBVrw^BL}Z{~t@&7|_@M zwzF+6Yb|5hwykAj+2)pQ+qP}nb}iRx^_+hH=WTELo^w99FWlEHIrY-C0{GVrbrsax z0=}TWD;Z1iv`}4p4hA|lmCxgA-0?>x46@JRDHXU!Zj@eI{+%DH!f(2={?uBA7G|t` z^!A?{W98wX2qIcH}(1GS^}I#7wjFOGG()w#r_;R)itUR=@SNMf;`G zsX2omL0kHiqbDtI6QunW3U0|3n1!e*lklx^pS9E8C>3WXw{}E}G0PtIN^A<9(ztLC z^JwE=ZK3*5`lYwg-MM=ZkmM_uK)F++A~%sDg0U8kFn9ILN$A&)im{N;AX<^rfnmw% zsxlLjGE?_dcMkOWpOJTiSIIP2TXX*pqoMun0@eKGdtlO5PO`q)B<8JumyXYS@Tr8} zzIc}vohqvtivVrfWeyZT&(axYP3b)3x4&E9!oM#o4C^rlUX;ttGJPf9SxXKy(ZM94;Xke#TkWp7XgYb>@3yF2XmH?%u10$>t`H)Ur{DjT?s z3~sG-f{Z87JMu2Ib|T;MlYlG&Gp0_75E6sd#?svjt&LFwyyeDCP2|5u8IWV#f>U>4 z)6-3-sIB*}lU58#uy2B_BevfsIqi;zgt^SAfN;8=tEP?l)5yxFD<0YtsxzNhp0ZwD zWPj~%NE>r3CSccFZ-1b07wd{$a**~dg8?a zrh!R`OS(od7zzloQ_uSBCs0^yc<44GM28D#XAWQB(2N;!_!*0FcfqHrc=syKY-j5l zix1eE_l0bFp@5n}2M8bO=khgRgYFgJ2M#hz^HBAvf36~Bzx6mA2FFJ1x|0G0C@NHj z%8l9NlO6~0askMvQA}u_7z;FU!e9^<0JVgGfpt$C8nReh9m^wOeh+BLW82-X?$NpI z&*DP0RaqnJ@zRp@%2afD_3yNvo(vM#wHs(gnsV^t0yb&~c-UE}iDT15lZsi#aI}mk zlcOWy(A}#qDZcW*RQ1R`C6=lX_M6vPH7T}BD^0sQBnQ~j&{!#?%6Kio^3|)A;WMy< zS=64Ze^x^P*_gI+o=*{&FtqX%UW?v)CFljYjfH8tND>8fr%j=&-JTW2BwjfPkkQg zk7asi>2MDFUg%wmu5I1AS1NWSCPwH$V6U2>_(ebEe;w?C-7|jl6a>HNP0aqa2m8Dj z=-LA*e;-$jW$9Z=3;Df)K>P$S`9vd7@Zk1CK`;;qa8=3Dt|83in`f)6+1W1Tssw_M z5D8erPV~M@uAvJGS|40_{_D-$;U8z#ShRg2v#y%JD_9PndV<1vAjCgI(dDi1b;G2fKm{w9K4N`T(#UDitL2` zTFZ>wn==-cJ>Q1mYW~1FDO`eGIx4Dg{<*7xpe#MuARmZPZQch19lfg7naO(3|6vYgMp)+H$XKjsR~CkElv9~Cqz+F6HK!# zF(d)Fr>2e&R^{(etojPX zfYQ)ObCB%CR3DY~iENw{8Nx!>o&&;+ItB{|HHRF4*n4|n&UX!L5A9h)xQh)-0u9wycgbOb1CMSbDH`?hTJ^$ z0A#t01Ca4#xr=d*bOdYUli9~JhNoI7qenZaXsFhYux@lm|3}wvz1p2VyllAFXFv#Y zRVYvgdq(Swo=>cnn9w{e%nP^4`T#a}ouRR-i8dMUlORjm!jUIXO;rn zGlz(2=O;;^Lu&`qGvR)BzSQfh=S_x1Y6=iE?&274Cz8pA(BBdC5el~z-_@O5(fu26 z1NpOEo^jv40wWJMF-mi{RJ+)U4Z5By1t-)mUg1ZzefT(!0=Kg{h$yk+qZG1L(UHXV zvE^V>Nln6`JH4*bbJypeXOnBL9yB!fX4Ae^wpy6*SbR>-%J1WYavPxMM-<0{(Xs%d z;rZtDI~*T0{W?cNd)G=Hg<^n#4VSFUkBJxKM#lM3Ik822C+28jtI2GuCB&u=yyW^v zQ{xl`qWZd)_dv@wtBP>LFj3iA7Q$>6s4P70?;^+w?`Do`3zQ>1n%AG9?mie0CgJ{1 z*Uov4?DAh0G3d{v^s_%cs)YncUtgtOXul_YlSgm*!yWl6DQ_BO{fF2e(Z161i)z&T zoK9(EJ!Ue+ii#)#|6JTrW8f1F_8sSjr{hE4R716}ezzkrajP?O$z znS@xpf+3}I-3qIU0r5oO&1tuYpZ5i>@AxRZ@3_hB^~6ih*jhR*rK%K;HKyZ0AL4B8 zXMsCMVjVLMRJdl$L@Ae1in`USUYmiOd zL|C&K8llg$j<`M#FcKD!%kQat+}+26fq1nKOMH(*8Ew5HjlO$`N9nkhfw0>XQJ04`DrS|JhyOYITP6Q<_J0SQ z{dWg~!tS}b-{AoPV>Ue;`(*U|=B=$A5a~Vov6{zyicMKQMf%d+9!4Xs_6~CcG2UEU z#BEdF2Rkxvv0ta5%JQOmf|Kd;Ts5(PEgC~a1d{>h_-FX1!8m3I{z zzsY_}+U>nE6W?gX|0n*Af`qz`IW0qX7neYJL$pul0j1T|p1gSw7S7-A0ce(6@5OW%Sy=!p+TFlGle$tN1k z$x?*L3gdY2Ol@Q0y-^OFMxXiD=?4c7euS~1Uno*=`;mH&5=hc%q~pA3}d zjkZf;ojwKQChr>>Y>IzA>Yr@aZT44|{``Bw@bW_v27y3si@Pi%ceZyGyXdsK_sthv zZT{Fr zH%dy`Tcn4YmddfiCeM|u74(df8~rekJB#|{Z^S*9+qjHC{VqlLPhkysJ*xrn9K$01iO0@wDTDBAoTN1UC1LsQ;In#v_E) zkCa`!W;Z(su*}}k`sya>yd5Z#`sMJg>+##+Otv%b9I>PVGbufOjHB|WM7m??wmqJesvOVz~z-Rvjw$M^ZnYHONV zitU~-h=HsI{WRQfB~k$>#bsakbqJ!DC2S*p!H<@3S!gLodO1k4QTb!t_Q!=)U+@XZ z4ey7jsyQwK3}SP`f529P!;Lk{G79u$*);(J#8&o~ZDCcuP?i=`C*`k{zt-{~}REk|J0@ zGdN^HaM9aA*G}p^3KoJxt9|kC2&3h!6lL<$02%Q|z@V@AbgX!clx8IC_+sFb5~#E{ zBe!XMSLH+=Bg~3@8&Y3p9#}#NhBMflA8bQ|G?)RY3%X?qIFLbECbb!~Wt3IFHI_WM z8R0+Zh!6KAEG`DIX^j&h)(=$-BeUWtYl6|xTA&v_TC7)D7_=FumaBH7=dR3+njPQf z=gv6KwRI~wjM%1?XgpDgaL_G92pF)vHYe*nPSNRhY}d|v;ak|;12Xdm5YPiuvMIvm zPl!hs@X+Ic#U&F{*Nm&)L7Ss@aKzCQgvMDDS~QJ@As~?YO-nOCWJ9+%m(W4p4}Ahk z+jHD5c;Aq<@}fyBP(@UbV6aw76tRl#EdyOeu|9>#99?t7WJU^&+)%B|lv{E}jzKU6 z%DQGr`jRd$8K-;hPiu(ZvDMnEF@=i)I5rpnr6k_(ye!^>6O z9F;WvK-Y{P2_TACAe|e@=AQ5s(5%&^bXuyp-3Eg>H|M?jmm2zlur(DeIAA7tg86+f zc4!d16z@!a%Ce848*i_^YWR$ot7@90cfeEfX!9P7w_C4<;poS*bdK5)sUOyPF;?P+ zZ}r~e_23c@iLQD?Q`Fvz23}CW#}w5@gyDmLPyaGNBPu}8)+uc)?9uoJ_c(*Hq;{Wd zow^3|*B=K8&Ul8Dk1{|FZ=HXnmYg4VOZL&g#&RFTkX?ft;>E`Pi=a=${)|IqDhjA7 zo3by8`7FjyufhW#NfkzgIS=_z@X~_BGWUm0w>%T)t-rB4N6S+i%hZ0>9D)YaTo#jn zCtBDKfhXuv5?n|a3WQ+4FaB)EHB)u)<1~i|csZMVXonx;c&~zly&+!yf`4nRPpXd2 zJrrs0pT<4n|Et46SS7GJ-VKpHgixOY#UA>q^;^LA;*Vh0f`fkuXnO?PW05*{A2P0d zOjf+o#V4c8U=K=R??7y-2dGd&KF%bx2CPI6^s?(-V}3O))cvQDbPv}m?0K!E*Eo(>S%3v4S%@R$(n3nlE$`*7)S?A^|tfF$#}U#A)znVV;Q)q8K+{i;a;MDf2 zQEBUES6kwN!9>U@Ierfj_*3&E2LXotI70`;jn|wj$I5Kmq;<>qX{|42llA(kV$KAt zj4`W;N8|BtZXHPWnfGL}^=`A<^~qLuN*iVv#jM9i9L`YZc+lrq=Ham``hQH>qN=8( z@nFDFc}?_(b4-V~3<5#}p?78;zcI0v~{F?gw0ul_&_AjFOt#2-- zTTCVGVYDIZ zyI})iG4%9HubZMnFm26?Rz7D_7MmtSP=%thI90tOoEm3Cf_|;3<@r- zNW^+3Ex!sItGJj40Yz9b$b>3Egt%kTX@5`A3&APT@%GUf z^VX7?;qesXd2a2T+**QwBsd18{VyX%Siz|YI8=hd!a+r3lQl9^_ z@jYNH)py)gw4E-Npq=5XN~z(LD4R^Nvv>a(?;`2<2k-TZOYk?x`q~Ok7PPko64Mz3 z(nG9J2tgWX?dcQsOG29%9n$jzhtx(#H&ljz4hP4+kUT2T#^U#?!DZNN(efP&K`}V< zVbBj88fn1{6PlF#9wT*WV!?nm1jw(J4~GSBKFaTIzItAh9Iut=h{^5lFnlZw?Ft z1``&I`1qD}g#1uuw=)g#CMl_ZISLNW7|90|4 z=cA-Qka898sf&8vwuP0hch5)?MT{RczUJZ|*k}kQ^O*Y+4v!J%#?eE)LOv(`C`ypn zihLM8FL4kA+!-tISDiBiBTyXhD~#(5Oxr_1hz^&vQn3)@;5x#qp43oS2Sy+>By?-M4O0{={f#` z{>dIL;2v)WSHj7;PY~g0cw>o1LSG2Qpriu*%FevfZ3QhASVYR}t0EVO3oDwGmW7$# zbOYb6uX)=eP;e+{fXA3{5%l98L{Nmmh&Zi^wpT~s=(2VB2`|Q{?n@poHcl7D@wOsm z+BsR~xpq~gqn+?|_P#Agd~7F3H%K(}^GV)Zb)p0;4+z0~6mKD0i+&C(l6dKvxQ^>w zqF$sjQtKNM6FjFex+zz`9bsP_V_QE2eTNQ?-J+A2F#U-8@fZggMW#B)$UZW%cYJ@o z5Hn)j^ChjJ5c{6<(JU1K4=Pzo)56Zx=E(dHohK<(P5U&36gd0JnvM^&P5St>Jrb0K zJ0lVprX~VoOW_|!0{`CFhq?!R(naYDM?x#(0P|Mx@QOr_7xAW6Z*nQgR#5J9a*4Sx z#3c>|Pr+R?jz0gqyM>K-T%_NKQsR5FQsN<_@EaKzWH~<;o^BtjbWEgQAA8qosttqv z8NVRD@?ENV_q$>}PZ13EYJ!+)?639Le7|P#90ltsk!?R~+36>3NgpWy9szAwbJ;_I zsr(;hsAx|$gkL9Ky`f>yiGhs>6~p_=sX0PS8MOsk+SvZ0qTiduh3C?ZiV`Pn;{D>& zTUid4mShwdVMRSM)NT=LfJ+|wBJdL%;Ee()iEmCr+{7jB_uo9hjbC*6O-aKR$^9rD z&9n5ol$znxn%-wbT?(&>U@mP&ip-OUGyx(}Htrx<584e&WDSKu0I9?MfC3&SP9pW- zcx1@M;Yd;h__Yf?AwJ)Jtg7N`0MxF3XBG2LiLb9J9tk0^z!K?j0ryrRfyJ?4!TKWl zbNkuS0@z^xBsM_gk~hRnDi_8-qN(*H8*ihn|FuZplrtHq`sh0^E1?Lp6R3j)0Hk4N z4N!y$7!cq*KLyOL0XR5zNyJq}LNi8})s zwm{D%Jsg_c4rJ{0COTkx5ky&1zDj=Nfjm%Q{s7M{A(lNY8Yr*xlV?$QIKG ze)3!O_lZ~6CQ2&FUw1C^9nmK4;z$3BlVY>Q--wj&Bv2}Qyx@a};p3MIy>!UFaWHZJm@9)GnHj;uvtFWG2 z!mrB=i%Tn7^Y1|>*E2%2&W}_3YMD+or}SO$w-I{=u`zmP`B4@EiMBb&YF{n!`jiIu zkad2{jjZUHmtG?D_fx?$+5vb3@MWY3+L1cDSq=1is(+$Q^lg=j2F&10FVT3AA+g{X z5_)ySPx2-VQ%z&}8`iUry08&nSsaIDGsZi^!iep?XDv~LV73@tX-T4%COT91pQ~Dp3e{3k z5Nc2g+$d?zNP+AVgU`$2FKJ-hx_Lv~`VT3(rv1kwLZWBy-0VbQQvOpo;pWZ4@h(Ar z?Xtr_%nKKt(c7$&o_r%#wnVdO-=&AFPuvw^fEB`0a4{C!1M^U1V9JoItGK?29|eNa2Lw4h&N#Vyg1qYB z(+ZQP44hR#BY8Xo_@N0xJRV@p_jha2l0+8z0{hPlh2C@I*jBt zoz;v@;J56|?&>Y4es}vsnV~YzrJzo?gu@+rG>@(qOZl0b#Vl%`CJZYbSKk)IB!Egl z9Ps537I4PPumdD8fR#ozG!v>;S({Rm81me%B_-n`8C7zx5Nkeyu_EGq%7n zUR}>=FUnx|U=ru_D0q!dYCBQe-VuOB7a3(t*=r6~-m{hezKQ zkB3grtP_C@WW|6GYUzxEzh6}{Y)1yz86o#E{zNE|N6-X$5l`#Xt^RoOIr#yo@ZWcm z^DgF7WRD>eI<`PyY}KW3TJ$w`Kr2Sd?2vjq-dkP*7&|E`#n!Xw#D2`A52OOWJ&sxh za*xs~P?R^z%I1na7G3)7do)N@B7}$tUz!M_D$RrRj8vgp$72UH= z^~25u8{xh1uU;63DjrOX>}^$(6V;=Wk3cdxwY~ugjK+-aPxfuQXA}9h}?M^$#y+7<1<8A&spIZj6@8naPrT_F4h>=Vg7jgs^+6_{GC+f#2 zwYD*ziH*#j5A17gY9K`gV3AW>Pt&|6y`S2LGO1Bv?&gD$XXOOBLBiX}1{!sWHmfuY zifN#8j_i7RWcDrrw9=-CKeOtLpYDbOcrLzMhh4a$?>)Yd#k zr|mIsFf&Slq5*`E5%#5t3Q_a5S0GYb;yWDdPQfA}QADVXUZOXgpL4G6AR2h6>$NLw zcd*;}OA*@_uQTUBlNEyJL6(dOFxf8sxo%koPgth9Smr1wgcX+;PH*(n(n8E}e_khu z@cR{ciXeQhsZ9xVg>{O#?gTL3@p7UqSv^&()q7$w>l&m-OAA-vQDTXe=TMAP6aTU% z%%D@3qS|r3q}y9Sn0n2qOh|3==qG85LG>$rl)Y8e%ZcHLSl2{7%85hLamfR0M6LkX z(!;Et{n_l6g9YeEukX>w&6B1)yl|1*@gnl=@+l~+@PzNoUT9JUBMhk*eccP9_6;KJ z(%qrNpZ$n8!Y`-t`SAqZL3o%2;a8M5=XN^C5IDsHEn+A%ziHX+>;E|F;HcLEb-pl; z`mTPhiT00!;=N~jhJYj+3MI9*C9F}g+P29K=-a2WD|3>RaKt9cq;0A7fm@c0e!jd^ zVkAS=o7Q&HZ8`d$*u^>4;pm<(#4hqy>Gx<%w5oU356-Q{K}|Au@Fc*R9_kIsbcdw+ ztowJ8@e&@3@)IBVx(D)g1iL;mRE)N)3{OAgLoZgyucHlHzg?ie-IK)T5ZMc@6vk@pR+`m|75#@UrR7a;dGT5;;NL4I*u=)ame1p`O2SvI>bPG0JKN_Qpoml7yXMR6&C8%Hk3%UHVP+oFIy}wE z`C$E#HiC)q8g~J%2UnRco|o%(R7yoR`p+N@;FxHO*-fIecVYH{c_ILY$3Z3w%;06k z8Zv6yVj9D5X1NA1dPqeJtqu1@Bmd=ISJpCt!Zm8v9DGj2VFCqau;8#ZmQ=23C@yr0Qosmz<}o7& zJzwzpP-x$CY^1H%QKLq+EW$si$0=%iUklu?E!sCQnh)zPwk$|w7>xrf*|M^b+Ljb! zgi0!eT$d0FJTd>SSguvVWvYv(vTDJWi|j~=c52v$m)5vI#dTXwK%Gwnou>JPMX3T0 zCUDb|=6Av9XH>#rC~N>K=X6Z__Ee=?2St8Wj%OnK1?L$wPdm7cE04)2U!yt$pHckGmYP(X>;9Yy1`^&diBa$#701;$Vz*~AM z4yj!3q?23Nfq7p*tSa#**oT%oKBY7ymc6_TXRj(BRXV;xu?VJ-vS%3FW}WDKR&eX2 z<^t0Q!vQwj?H4#rnHu8TGNBX zwu;%T({uN*Lkx&~3m@5OAarTB^L~B4;?l4D^*Y&JU-(2r+wAM?uoJFa3jBHRoH)~8 zK)oGQV2!^|TE7m215s79eTCRzy7iboPST&3Ra1%Q);}daI$q#c0Vm>OVf#mV^^;Bu zyK^jRgb}+&@wr9)1C-0$;#dkujucsDk;yg0*$V6x1z+98x^w}6mVRAu`XU~09SjP) zP9nsi)bB!cI^`*UBD{@2D0}26s3*(7YplzEIE9MW5(JZnXQ5wU<|MaPZ?)A9eINV+ z7HX{titqr|}{=NPEdzBOk0Odqj4^|?-KBQFzH%HJ|3n_z4Ubbu2v(pt?%L-7ylThNL@d0hO@ra!}_z?lF6 zW6oERRA0zuA%QT$7^MxvVJoF?m-2MuS#@Yo*i#}{Heobd}tII^t3mT1$rt8vRl zXp?_zc z#08aM%CL0qp&AK5J}<7kdb!--*A}ZEUaG52+{EQHH|F;HfrwkzxYU~GcfKJE&*~NB zq4=vL=6{zJ-hx$GpnmOXQc0H7EY0S>92-_&Z6;cHc}kXr1B*Zd7B*Y}>KWkC25v2d zZHGh$h5Bop+e{qUZFf~3jPyu$$ZM0VCvhLgdGKdY-3;~HcmLaKTbK1TU#f8}l5XFl z?M~n1#pQ4VeVhgYhUzL_^oggxhup+`4qW=Ka(p1wBpIkIUFdrZIMm zIxS_6rfHd{#PydBs=O328tB?-)z=Y`nT{X@8d^;BE*&A4QE2BF*T&BJ5k44H)4&Hv z<2JsIJjc&Px&)6{qsM`_0Q;T`7Y~oxBSwHba4rsEM>rzL31%~Iy4gi z0x(xwLS20dnAi_nM^C_1ZvlPRr6hU~WN4NO>vCxs;;YP-VLhQ=w(F{?QR`w`I`0r0BPAz5>w>Mhw@2I)^5uLv09*e|g*hKGd3sPX+)RbF^1bCH6?o0Eg_(hpQi`TlVdr>* z%bYv${zWrX6)u2_Z?)3irjZHxPsS2zCVi1^y8N2($UL*EN@@@!#EGH%OpTLc#famNZGLh~O(0K+&F8E()W$di+WmH7cM`?vM( zvXgbLacnzK5e_JfQs3w~;BtE1)F6ugyL_>6oz}y|&YPHiyIxnLOYgk8zZi8cVOcKJ zcSzsb4VI~6=>s(dh|etrRG$y$`r2Em-V@>*5FqOOBeTFinF$3U4!4J;#l=x23w7#F*;b~Z*)+K{-UHq+PD(cOFp3Y7v?G-7ZGPEcT5 z2mhraku?(BWSuQAgU@FQ_RM^E%a8bvk;7jahRBdKC3hexwJlF}rFn3uousD5%Mi9? zP}i#I8hXN_>j>@*E^VO_4Vex1NX`kcmlAy?w)qpLW3DWH`qdiEcJciJal<%M0{iDBc+D_(3w^qb zp#WC5R1>U$0smz8SUL`};B*LXp3~>r;~P34pU!PP_)jk`;i(ERlh9rszEnNmB)wgm zn3dx|0ZMMADnZfTTKK5)M$`cuYX6LU4cle3n;Yjj)(oplm!deevV*ElM_n2{dQM`C zI3tvx6vW{}J9Z(fJeJQLq9u*65+6Ui5}&H+g0M6sv$Fpujf^ize(>^#Fbu3pxtY8E z2~{DR+I(%Tgg!qE?l{@{e23w$uGl+g^5b}R{dxnF@NLLlXOtyy{18)vEjn=Atr@gt`IRlI=m_tKcfwwDA|e7n@mqwA*W>d|5V8wgm&k=jovXE?_<=3*$Nx*T;%rJI3NL&4(W0#L>s_I~o+Zt``9R}b0?PdxW zvccGQ8@r_Ip%Q*VB7hXmp;nkPxMwd<$`}_U2gDHb+k4&%=(u~{NasQ@b*<%PpMrGj z*9_OETnL)qtM)pNjqnHM&geo_kI&s|-zQf|DR}5CD~33pP~6+Mt9>3^h<)@`Bk}ypse4;W^~Hk+ zs~ceAM5Q3uaP+?@=Q;tD5GO_HZyE$5CBX_a-!@+FhLLu+1SCd&`$fyl5Wh}s4c}_( z0Ry_$4|w0apvxu5diqQW*$=y!D11QeL-KJI5{b zjw)_hLS`gU3dT~#Fgi5QOA0xKh1!`1SmV>iH2-n8zJ?d5JY_zhQVRA#of}udI+j4% z3qQ6qaC^$)+K)$YlLY%`i-kIhWX5R4uetuIc|i4r=1<8jjWv3bd90qg+NKhX|NBX7 zU&^*;9qL-E)7F)75Uu~|swA6Hs$x=*+yGzSdV6%XXkSVeeOUN=)c5)XQs}6l!v*b? zf1eh}@cy9{kBNOfzSs0MdHvC@nIamiRRVhUx8@fU7|Jl@+gfX3#(O|)7qe-j7?wFu zyGTF-PJ@t|zBqoPafo4`bPEYezaq#YW;LyyY1P^_x8>_4=%kgVQv?vnF(@nSCt{HU zLXf>*mOyj2#pyQeDY?o#4sqWjq6i>)N-!?y=&rpOxIk#Z0(&nLj$N0Qd^Y@(eSF*< z$-z`&)uJuHyWPr0)g?36|0r#3bHw*YD;1Z6UB9yo={!>gE^hTSKqDD0>6!;Ss zm7DJMda?+=tHB5X!gu%hy{J>8o)Aa^uO{K48d0kro|v@tU0G@Z_om=C+*>lOP^{Hu z7r9h@Iu0e^;M(Oe7AW--%U2;T`sCet+yCxN@8W^Gkg9RC=UO`~F)Ab*lX?G(8Gysp zzK_(%C94g1Q?pfe#O@62W$R(Vu(Z4)#kuf(tq4~>mBzYP!Y{qBz21^+f~_i*`J@oN zzr{vV{F_;%O8{8JqbDByHEmspy#&N1HP>5H$wnn16rc$~4;aEo=jF41o_|Uq3I@4I z&?PfuNv%OIUF{G4YM&QEBDHEznGsm?j3+2G+Y7v56g0eqjoewOtB@R35F<*Rrx0(# z6nTd6h_~)93$R*O%7bu$#NBDH_ZH1(+o}Il{O2l8KUr$F<4-P& zlNxE`jE)W%txT-2ghjkn?oQ5J3tP!(Lyk)LQ~)ifgv)&@-aQv1T1oB2{E$?MVNVQW z`?L`O?0%ZO2p}?q=rNU1C^r;!BAn~VCKL(cFBR^0o*@2*y^E+&H17fY0IRgsti2X=y z8Vb$c#YUHI#N*8eCLt!{z(zi#9^W59uOd{Xtz;}4$pV2cB7YLn z#rqWJjtg3*X{=6wvillabvYz1-L*R; zrjhWRt-{~KFa&U1Zp&tL8G{PPl*G-xvdp@Qxh;f}VgWDyC%sabdp!-h$b7VrNhNDZ zwJz0osH)5QY8n)XAp45e{ORejRV4&TM50bXCs|ceY1(jAI◊TfJGYIwOFadSdu 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 z

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

a^&xx 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

w^(LiF`aY} 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ŸEPQ#EX(0oiqP*Z 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

lJm9|y;;JRTts8xti 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 tP8yC2D8pEC)rDvO$yat;B z35f)sMuN6m%dmU}C%b{d2OeG&^6hsq$Ip$j4jW9Qug+=5E@VOeU`|BsBehUuAXZAQ z6mA|A{Fyyj1DL017E+Nis*2RYS z0B0ruA&T=(mc<#8+Nhy!muZY+toFAL!hxCax}kqVy0L2*WML9gw_G3LRKieUC!#G# z2kXrzVs+x|w4tC-wUUHc-cIaS$iC(G+55LgLIeK_jnA@{ik>vFMMFP-$iCfPds6eU z))K$v5m!3Nyru0dKV=V6hAik+MEA0IqvIU5s4b>C`RsN7ea_AAMzJ%*qH9Azu3PdZ zXf!cyd=}1H(O8SN+W}?AOGe+XROorG0r4G>_Bo+UGX70RLtcL=&HcxUy52Ehb)@}Ee>?2M2hw1 zNvt-*kQv8Xv-PMyS+Ys(0a^||%#Vd`V+~#sncvV(ayLU!CZQ#cj##zlO8z7kzK}1I zw)t@nL)st*SXHyH3sdNISx`jeDDY^~Jd~$KOgC8!b+VurM2O~+Vv4CAOYD>fCG!}m zf77Oi=CysxG#NHBjHSfb^g)B;ZCyG1H3jQc2Pl&1yk4Y2nl^F5-i)iGuY~D?EyPb*RZ}QQ6#{2rlEZoX z50C+d0sUF6(PadXGM0tm$w=@3{9jaqfm!_fHU-<+I6VfKM=>flUM`B#h=-hau)#C> z%%Ou*g|bc`F@|H}S|ygvY9K;n`@V2A!koJKi)eE_tGDFvL7kk`H>*Y=I;bP*g)W`B zHq5}dl!8hMqQu6hC!I5i6w~7!|6Pc|-VlUF$t4+0Avp9~`39AWt6kPd+c$9P(z<}z z=;9sR(vk~`9u@R;}esZ;G5 z0kO+lh~>o{yQb>d(^u-T>jxq(aX6&)jYyOwsncpFm{UEaySj4=OyO9fvb7DDu3Jw# z=lJru!_~bL&qL3sy3_1CD-(35gg@iH9@}|L{YNKGctOyt)_*nHjbIsD@SJgS%TwcE zNK&B}goVkwT1d{44A3%-m{pc`hg~}&lYwbEsR;PvcY#Xqd zm2&X=Ld@BPaf-%vP?fU#5>DK1imzG0?Fj}3d^y02HS$TI)ov0ptaMeqO>4|lCe-*z z6$ONn*&9SUaZvpDikkUINg0S@fOx^v%BAc18PGrjBH;T+XI_6h$H+v3a4s_W^VIx# zfRMaSKnmE{UHyMEDadpq(PI>?vkLLeD_6fOsRZ7mnyLq!MFM zF6-TnrfeFdf-ea7Hs(MI#3|)U92N-8rP|rI+FKrwm&>zU;(u#9=Ps22qrXBn}VuH+wwSNF$N zhh4iRS81KP9^WMg@6Z`2c+hKFi?hcY$Nq}&9=8z}4Fxuo4G5C_A{={bdg~g}x~7yB zc{l3Du?6d>!L`tk6#Le7k)Ysw)j2=EzCgi6m-hlJFAyS9tXXH%AfD2x}q2#1;SaBH9S;vBC=2&I_5v*rS{_?vl1L?W#E z?&EO0Q>*>n;;Oa*a)}+^2;?zbLt|}t_N2-^cK3%R3I6!;H=zR9Q`ih6P(FdJt}W$1Y&# z!-ikf%Lpn1M%5<;{RB4D$nu*ou4mjlgP0~36sVx|BpL1d_L7o?Al^U8+@~H>%xyNQ z$CV>`0=FiT9InEqX?KS}9IoGa zb+2~8kGBa#IXN}=TKm05vN-jJo8Xz@cQFZZ1*5O+8#cTRA)bfp2{n<{hTD&AP+s6s z+=TQgiMVQ#RI?Rz!59evP0)81KT%)O24!JwDP!v`*4(!^nRc(zb4t5ar0Q<&RvuQT z(=r`mrPtoB;{s8J!F%Zw?KuT%RCSu$E6>|%=`}4k5j(RizN({R3ZQ|(OZLVQO%mfEHzIZ7J~EV-5} zC1&`1EO015mx8=fs}rB72C^Fmz$19sGxX|J9V>xH02cZe{j_8G?a_3ZvIevE^lq!e ztzEJq0NyIjp>E(ywquJ2PI5NA*Y_GxF_4&3>)OSN=QXV*+CR_z2<{JX9QH_lW+!p) z;1)Ab0&vCAz;8+js}y(+xi>q|Iw#`w(L`{YxFx15v!eX^iqFp;TRm0Wsm~|Lt3`0M z$!O$X!8NNf{e!E23?|2eurXRgail@>&9&jEM{^S9#(GTNSG?4rovIjOysB ziQxgL)xzt{D4nw|Vg>5}+nw-ZPp2Dbr7=k--h+x~CW)+!s>7k4d%VX_!1a~=-4Td3 zWbSoaV1Wkp@Y>`xIb4Qt|DI`b)u26kNi}%ofm~1R3oz6jV*fS`e*=d>80H{+_eU9t zXPA(G?dMxwFj6VE47{VC%JB3*L-fFazFezX=A|KHhw)u2f^*0TF6)k%cRizI76iI{ zSA=qk$UP0TGZe)hS3K=-zeZW4=YZoHR{fkbJjPD6)B>a*Q zuP9--r~4BvEHMt~0TIv-TW1-j#rEk}Ie(H~T6EA*y6j=2$3Wm>+>o%VwcXZ72){%$ z7T-gBEO>;QO_9d>IszTw0QlnCG3#*^>R+A6n6n~Y2^ASFk0qZ<$G|8;UF5M2)3Qz| z2Tj{^FR#H+G@HR}nfy%H4XA#491`Wfh6aQH^tzbuf`lQ}55%3iad1y%ZYo(wra}#< zrMta639$l|X-$o6QvW30-7P!6RToOf&t-K|LNC~AkvD#UG+H|RlruGUXLc8@%R@te z)?yI%8iuYoj}-x{S(37U%}cUxn6%o-I&=WG6Fm&6`HB}~uItzcJk02VExkb_XoKY zevImipdAx8gCFz5F9j9qU6FR#eW*x|)3o~MkG|+MYfgyYTU1jf30w@&o3R{VHoG6F zrcP7cSa$6`O-tC_YojufP-oKR@_ZaG_OKfZ)F;v^4%;Vd)P`{zU7?qtqd7;ZcwR3k zN4iFtdvgq=8t94H3Hoi2oL878r>)84i9E4#3w^W$I#P}T{hX2HL7)%RJ4wCJ&)qj#Sc|&A{$)Ga4-#PG#V#_{6^SAO*ER?Z6Fg zHDc8iKL56C>b%AetCUO z!56C}JH`VytLi9!1ljTX(s(sx%9#~At)@VW_os!H<&+_{l9*WxTxaf3t&l}qEpJ1T zb_(wA9~WB(~_)xqPoZs+HPV-oedRe1_X zC;Q5>rNBnCsZFLH!|&Q&$b^964LAfsm?~XOWY5?*tYaJdtg!70aMT#UcU`U(AjScX zZ)s?B6u1E=b~zE9s;Oo4V>Mg-Z7yHRiv>MPiN{qXIx7BO){bJcsL#2jNQOT3KA-BR zb0(6)k8n4+skLuK3{$^m8q;|65b(n;*!qRYItG1w+#Nx%n=eY^WoZwd*0agB&kS+k zqzEMSqJeboKhbsHw)>`)3=T?dcBLHs?|&TjlMfpx8#d32>C+)$&b5;K&O9<1wBJ=S z4d%^!EB0S|VFGPkS_C=QEMEG>aRtoX?owHgI9}Y14e>6CRg0_}XGR0gI4_yAe6~ zlhtejPE)}DhD;HJHz#ag$lsNozbJR{_TTVXQhP5lhZ8vqQ>cI+C$?_t3?uYnlzBrQ z>0@%yz67w?e;KnjD@x&&PUtz<= z?JTSMwF`E-)zrB_?hftXz<81`&~rLWM#BBAxBP}vWyP=-}%2$Tg~g# zH(}rhQpAIKguJV>DKY0)7v%G~tzb@0DKXuDvug(CFmpG|>HJm$lMX+yf38FA zTV~kkIKPi_!@_&{07pkNwvjS9o2aIuFT1SJch%UnC|=Y|ASj-FhNjN7yy5 zxA+`f~PIELI*K&LMl@*5``-@Va!P2HA6V({eMm<+sHSeTXvz=zdD9 zHaTlG-}!_;d9H&sICJ9UPZBGaigSYA~!M*K3qnS&w1hmDa9j)jEt8v&K--b!P4lJ zOXauuJC4`;UUA`kIJ@mTO{rtEp0a0x;gIUoKuz8^O01oWdgF56*fO~N!<+`~flQO9 zTtNj2g6H`9lt^DHhXteunbkKi`I5O~_-gh`_ibjaf=`e5I!N4tOqU&)I8aTgt0&@2 zv=`XRKoT4blL8}JR&6po3HT~*r_?YtbC)WD!EPQ}-SpkXYk*;cKr#YpIlU~wznkV0 zb3h7Ry-auQ@yc2X1PpPi_f?ui!m5`f>DJD6)aj59BHD{B8hx)?IVTv%Eb#7uy+Q`6 zNPQ8<>W?ZiaDgx!`#!m^{q=f0Dc!4zXH@kN2HRU|5B$hXfGGVBiW-iOVDkH??x97m%Zyvw#!Sau9{6QyJLkj>P z1s>5#{Kv4CawS~Umy<``|6aiBw-^i5aW5ZU?PkK}7sVkE6&{tOx;+Gq*eeH|-j2@O zsdhD)sh#b#$##G8V&Wh^_Dd<5c zLp5-Y6{)--^fCzo<9e^pyiBgltQ4`QV6P)P`E|YN@jdWrHn6$4`Antj5{0Vh1O^|P zG59H^fbp{gAa53$n+x=n%??QurALz9Th}B&9^PnY!p~<_#<@U=Wyw1Mav&yfZxD>z zy9&8u#Cs&{4W`2r(wWNgM1k7di~wBtx)oW+4wKZeY{V1tyC(qT`Sqg)jSJMxzPfS< zMeDBpt1QBm2+c%8zB$B(yCLFlB!wMr5G<6Knj}PStRN~Pr45jcE5{U4g`dfYz*van z>{)|H^LkHB7B8W0E@XTC7bmh!(4`Gugb>@RoT4+N1Z@v6u%GlTkW2(KP1gpXd=9Oaz zc)lGvg#P6_zMQNDr z8!weHqZ^J2SxV?oBL{s1XRTqyCuY@1nqR~f;L#ckNm82TM)aYQ>9*|S_`T~tX0Z5q z6@^=AbsiVv$P(uQ0hEZnsC7mGUsMWex?kChJSRIO6Q$S#jDq@jk}(^g8|Q9_X<3N2 z?aylu&=e=g9fTb+rd7NsRP26pSR}(+92U4+c26F7_((!bhPERGvN=diYW`O@Vdh%N#uK~S{)E6 zN!F!kZ8~H^Dk@7Tac>{aFx5!g;POQrlQEmd_b_niZ#IZ>1I?aVtyFhoQga&&=$Z@!)OG zKK#w>*)k0HqCSRS(LV=D!TPpZBLQA;tAPn~(3R$&7k|(UtwO}q;m+M8m9>3E7NuZ4 z_$F%amXnPe>Bm6_OA#(Xx_~Y}=~b>|KQ?oUX@+M;{!q+cia)inr{O8HI@OU9;blMoC3@OVJNh=qQ~=8S98E{0@wHh+Mz>G%>ZopArNwLtL$VpSziL{Xz;TyKEbCDlpM-Hk3+-|2tspA3!`8MD4V49a8?RYncu0vfWy(QV&^8x&Fx*smz=3L<`ogV&JNQtN zh6P=1x=FCVpO)o-m81v4bKS?n--bhlRpN;7(cw+fS>3L-ScvNFGncK|Lp^Hkck|Ve zdAXzp5vK@XthX{ilfEARmd=lxS6<1a-Wsop5$oB8wMK_O*@lIMkPps zd!Qk?IZ~=5&FOg*NI4TxZd0)ky zQ6M@}l#HWmB0y1VUnyg9`GG~%8e5QPbxPz9Hk|?7OXGV70RSsT*STduClc~mmf#LC zn_k=2wSkr7Gm9DOmeUbD?egr{>SLP*Y& z_}2p!-`?uC-ihf659x~vx^RTUQR0XEd0C9!)A<9oqbtAPAqi5`o-Xj{Sf{1dsts#$ zv%_8rcLm4w`zSN7Wj(vnzr1^aZ{V{ZK(N-%=R-gc%SVE^Ybe)ThBhTUyJH?S9(l`@ z+E5R<;-4zd!JDBbz|G?c+DNB~N2g99W1-^KUT2I>5`2Z{3HYgJc8T_-4(`j#S;-0p zG8Xz0TfX+x+~WPwogrz%yiMoBS1l-P9HzoiAVEES4hKBg5aEcCz)ag<1UU9|1K!Rg zg!-m9p&STEP84IfM$_bilbi(6w3xkE z!nJRNXAU3$sAUIT+v0Q|>VAp+k=x?u(!aN!S3HA&7Unb~lw=$>v29S5dv5 z;>%92!$$@C&LqeXU_0Be9SC%wLg>Y-G~kS>gr65dm?>5Ak=hBA z4S?o#+J}lIC(dAby)3+6p}yCrZffG@HU5y?RWZ-y&Uxi@NMQN>9NP{QnnS67?Ghv4 z<7l33I?@)F6kmmbVvoh8-4}BBx#KGMDH`-QaNI@r#ugjlUOf)eR`5<=(#8=Y&`ACQ zq?Ffq2Htc+%eHXPgVP=!u+!jQU7LPu3Qf35c@jSb!&-Y#tA6l zDmSd`<@$MJ2K~4V%&08T(;rA5IHp;DSQREMt8h)!?ls6=LEjbyU0p7!#GX9yeZy{4 zG6WzmnC6mKs);N$O8!C(SyI2xcM9q(8#^+3vGgBo_O=S4gQ}+r)*Yp&UxPQ;J@4$} zMrK5w#w}$zQCMz_<{UHF}MFA z_&uH-pzAlDJ)S|$wwR}Pu~!R9)b-0pKAAPA_l!2%TQdbOLrI5hYZo2r54>x(MNa$} zt4*N!Q6Mp~vX~%?iz@(p0*bGC&uF%qTj#<|y*cu!X^6K(h-$LIWWrRw!c$Fp$w+!u z(@0TUc1ip;e;zM~l`t>p9i$4STd&+qjDE{VZQRbn|D`cv`HSpc+3c{iLDKwD8mmU_ zg7m^2K)EFmFT>pb?|fAuVBb#kwbxIakyT!ZBb<87p{%srTzFmmUFAA>-fwAjhePBm zv=AsNyJHmy+s$W_K45 zzW@$B%=DdwKo+>)K7S}(K;SnVfPi!Ko0dQ1p=y??-T(>cHE$o>1?KgW zk_7V8kS)S_>97d-4KhKnt!QaJUesu5_;a0i#p|ZTVJPCO-S>-wS}T3MS$1!Gas`B{ z%Cc{Xg;c2w>#q+PSFFt9bV>>6`w@W>jx6_kGV@UT^CZ55sYSh0IkueUOUrt-PF^%` zjCSZfX4dZ_uvFYVrtOygJw25ty|h%n%+}0nEs5$oDY?kUcj0wK@Kxbn=MM+ZWprV6 z_XYJUVw_?29EzV;FS&mA3tJFnD7H^YppOGYHATNXHt+=*D^mo304FIbGvdk-o`|y( zAKpkXHuY4UcHnRGtra9xPzVl-k7J^{(Sm^44}Y;%73;@)SW~~TP*L88V1;UvgLL-U z4BPn3{ngNW4Hz#@b+;<>leJv}-uEOlVgU-S{}4MNL=1)x74mfD@&U(8N?$M@Hwn6V z47B$Uj6i3HLhxXKEbU9wPC8AscLS!lW+;*ScR7YF>FUy<$ns}AT(<6j`67fS!wGz0 z*;n-7m()PsW7s!JSzW~%UiJddYKJC?JmA>PHfYwiD{wAcH>)qt!vJ8Nn0H`pJ8JkB zFy}F727QnHgSx5xr_lNztI*Nt!hP)J)Xz;4iSXxy1Q1qL^AfaU%>23KExO(2pS;|e zU|<^mqSpAvct#`K0~fHTk9*LwHq_Qx|IfI6#k4Uo$-y;01tI6r3;c75HEVsFC+ZW_ z9-EOoU}xRu{!_Ysp z_mk1IHLEey75kG3vPz89w1;=hNPW~bwI^Ht!lyOeTwx_~nnPTJHihv>B`rR~gX4Y! zQJIboQs%1DNQ2t$Z4gbre$-Q6NH?^&&X15h#jKu(bMZ|Jt)I9(xpmQZXRuP8+3~We z_wdlV;sc*>-#Q@olY}3=0RtyH$fEx%ZtXpSago<@@Sb5I4GfA09&tPa|L9tSk36|d z)4lv{7}oKRc8qk&p8i~6{p67*#|v~{#3t4QzsY&iXb5pfO8ZxJd|}=k+%umQ{(1kA z_uPr)ahm34?Gz}fX^$^NwC2ZUWqeExlzgQz=OY$iul20B?+kjOEC<=$c*V1`y2LH$ z9gPsX(PX$daar$o?eRE^;i!VzBz8sNzTZ4M1784cG>Od%ecb zFW+60m$p$e_d;ib>Nq+ph5U_Le0L$-_>haNo~Yto5fzI``g+ZJIzgtDRSRX!+_K5d zs>is|BCM58^9wrQRMp$AkbFk$S6nfCBXGS^O-#7pbM5W&WOcMPC2ho>}je zU+S7nQ65m}t0O;*$~}fIrv3`z{F*fFvDcA~^vnFO=0LsviRjC}E3p1J$v3z4th!j( z8}TR?_35KIFi5qEpl+neU3%X8|UD`Xz6ikp`0vq|X5R=y5 zK#rsf5Su$n#BFbKbfj0PV!%DkBvy`9sOchyU6TJM1m9Vv@%Q#t@X>6C%>Iit01CG> zm)DX_c2rl0L~=R1#K2$B+o|Ym%#oCuBh5Yq&Qi3R1QsP!LZCpdw{Kavi2m0}g}Q39 zwg$!6V(#4~*FH!C0@v?mUI0L`Wp;_5y6YvCRGTN*g?{MpybJ3D_TkV{I^pojp(HALcOR`LQWrOJt9bnH?ulW5%2%C%oDadP+@b-o- zCcy9Ev?h_j$tuEye^(g#iO&}>hTPI0*kMHD=e(jE+7NTrSzQ zaC&o(00$thjAFjS3P)Bb>Me()u4?&6i`x!ZR@~9OWtzF7U^#Yq%slOc5|RU+j9J zPP7K?Zbx%I9jS!9H}C`*zAaWX^y&LocOql2&M_9|$wxQ`9<5WNZYo&_Cp=!$53Uf; z8H4|=o?$$!9o>3y`uS&<0dbl(vzfRHcgI9|IBjGAqsV_SYkU6YVGF}DOH7X`h@!;A zrd~!xHA!|UAq;?u@?atU#WW=c2Ny&Rshgv9_TKDTz1+^r5zEgX4JVtrx`v6;vo7=i zgJ0CzWWwA(D;aj)yj#3R(OVsqs=M;^{dGf$^IV~~StED_PGD4bl&PSPFlu&sCn%!L zemp~9($uA-sE^*rD%51>gb+KFb*lSh9&EdQ!!6zdM!nI2T!DO@S767;I{hmEiqAwW z?BrpPJn6;l%E;rh7$ zRI@4s*;(ws*BD_21TghU`_DGjS8^LE(u9_$wSE$%x?h0tKDhwwl(=ki_8#Y-^U>8GZH+gi z=-bgrj*#N6gqCM4SJF-yrA+=lcqIKEd-veq`e}#CpX2#XG$=XK@o!{z(+sVCdvejZ z2invzC0Z$J6HYaa3iF84UQ+=1X5x!$(?uAss7XLhIcxWRN#knBA0pP7p&EU*=Z<)> z@d*~+Q}3>L!hAA~$uAaDiP&g@s*3YGv1+<%!#@0N&v8GiKJgIP|3(LdtRafUlms`> z%ImC+U;ifycAgJ2k8-Zy0@RvwuLnt;-Xy9w9@6~oo*{$8oEs3Ya}V>~U8X%>JWu}m z1P~O>2i0lscq2cXi^V~MX$S@t)TK&llxL0HPBlvdxJ~4Gp+*rJ2)$9@-CJ(lwheJS zIhO`NePy>z63k-Vf488e@g5MIMhYK<_eb)WJV0EkE0aeP*%AuRUv3T%KE zwi&!Nang$8Za54}oKKY8;-)X3V<^KRv%?e;cG@AbaGIT~@4(OA_woP+V?UyzG83H9 z=ItSoZal2@W`jMA>}j^^vRz4Up2Ofl;~x7bmE$eJlK9D<;ZZQN&D8w^mV4QU$`~=q ztX*4V38ix^n+o1Cwc4pA+a-?~<6P#WmsUZ~%JlK`#TxSP2Pk8Cwh*WHzZl=L zP9685Z5;bQ^(?KBr*hbB=dYJ))%X{J9BKhA)9!1&JVC z3SW+c%_kl5EX+5ug2FY5lafTZmax-O6}fe_D1Rc>bYqPh1`}CE6YE}bRWQyyf4kMUy8VC>Y{tN?q3GR2d4IlKqWIc>tOpQu{{OA&;ITE zYd^HjB~H@RxhU-;Id2uQ~L79?jT zQ$V69$S*^gia>NNooo1`9F#WFn;0a1(2e{mpB+!NiaVWk$XKh~c7KDhIrIeDH}@X2 zk?_xWkzk66tfQa>tqE9@4Xu7RUZW$)e~s4Mx8tVEVvR=OH@xd+_L((C-+_)So9_uM zo#e8wc4f%1I?wn=B+CTLlcy^g!^ML9KEs4#&?p5S!^oy#XYCE;OU!O5O<_|R)M6Z) zVC`oAjcczK15U02ZY^YYhW-GTi8Sz}V^HCGjlq|rfn)mp2Q!}qLXmn;vZ#I+{vCG_ zAaP(L*ZY!4tHRH+4;2kRU~FOuDo~K*uO)j=RcvgQl?b>mG`ze|^2`${iP$ym@$l(? z#VP?^p7V7=(F#}PEI7dRe;u;TDv1U}6cS1hAwaw$^Qx%v}wT6}>3s^~fmcPfD?fX1YL*y$3QIp3lYoAdic60;kcWmD&zGFRfjS32f0=EI4O=Ei&W$j*LuNO8Uj; zY{>^S1Vey%6|imMYsmRr=!7{*oG2mRynP3GyKdz#rG|?LFXw6BNzT@==KNHKP zWsZ?>B2K3V($cS2Nx9{yh!>xi3)qnL7I8fEY4>edV=tg{J&nj;!JP7I17D zT->(X)gYaP(ZF!Z*t|e+S)K2<6!q0G0hC#J<^sTn7l{QBK>^XB=a5~V=YRh`As7$U zG_S>`7L;%L{&oGuajRV7kd$6|w@J*&^Ko{VEyB_Cy%DTa!1=t@k2p-7nelw|ga4on zYZ2E<3q&$c0qtz06oR%jTVB1iHIhzJ>=62>yI+J2ZIxHz_NY>AjqkkU zy4m-IRk@duv8A|-GWZdPrg7ii zXWh=jZ*EBpsa1>S58DB1ce>4ZjdsZ3Hwi6^8`viudgUBb6YT&~07nw{DZD&anF>8o z(;rOOB9cWimXoKj4&)wT+tt#~wAc&$R3YbU&iMt~E@LVOuK0?cvC!URNhTYZ6{*M( zndUqAkV5xpbUOFdcL%}*TXDGO-&R+a@LFV)*&$1rYa)b*$K>J3#g+fZVzCVd@vsA} z#vYYA1?jiB)t2A2Px3;PvYqkj-?wIVZkj29vcsZKV7AX4p4TKb4 zr>-zkA8$4G(*UFsLT@kAo|4gubk&)xR?-f8%9nAB;xNFDmpZdNlZ42F0afwumhFPV zP$lozCk+IjsAagO7z{AR?i&sk_h&S;6g51kz{EaYbd;AM126JelIX7oi7X!dgV#@U z-m)cJOgp;wv_+_|e0D;Ix`DI4k zRVM(N8-o$B^a3^MO2^hrZTcFv*piP#{=#K9*i@r<)pEF|!zR=e5|tIgfAKbDiUxOj zsAy8=wdx?pY`XKIMNMX>PliPWy$FP6px?z$>*3dZjEf68%k+9s_vibm!#;s`D5T}*znbg6&@RO%`EtT(fkej6mL0_!o7j8q>syeo>w1;#DR)i2K=a9*|uFR zn-BdhmnP3zP@&!?+8;_l-ja==@bl}$l4FgwrYA)G>C^NBcAbo-m18}>U1qjc&V*hS z>jtK3s);VO{`P;6YvRj8%eXLzEdj>NwXIshA9$ie_On93`ua5+pE8vWvp4pMb1W@{ zE?N>OoK{>e9NQS^MoLA9y3a9Kyt@3xPbOz&=%*ixg$Ck(;pa^>u;unm>r(aA%?c{7 zED)k^x%>>UHq1fr>>E*XIch2$Eiaz)GC7yl(vA1bP=5jE^w8cr{TH5cOI>R1a@sE? zsZkvj;y^`;ajVIyWd=%W6$icMn$~WTBX93|2*g(4PPAdBjF=QA5`=ptXhK1qroN^@ z#Uz3{O_NL$z4KjjSN6UUb?O%F8KlzdrCn&aSWeNCU-Pgn9+PyYmdF7L!jZxK?2ywN zdT!rOoqhO9vc7y~EU?l1r<}{lnT&qn(<1L$mt~@muaqhC3!BTbrWru1ZS}a9|LQ1= z=tvT3L`{t;I4z>Ps-JOR#b(DMwuMu^TZ>X!5^z zPyZW^y?YfCrLtx|qG0Np*C4$Tzv*|em=UOx!{2OCA(>NbZFyKtjz3I0I)~DT97G>Io!++n<#de3K9eSkwFhlTbGe&~w^(_$}*6m?xwP)9t^o9%Gn+0+< zd58D##4*k#>uno8TOXw|XZd(!ZJ-?ucw``;PZX>j0{=aZlyQXM;HGXPa}546P^a0T z^wee$eZ9455L5yT(*;6bpXHYr_X#4G^v{qMxO%yR1Gvjc_SLf!tXZQg6S7unm9PW^ zcYpIRdd3yl^Tbsuk?#G(f;EBxGy~2xsbtr8^~jHc3G}XR9j&=6*ZxSDWzyx&nuxcFVnq zqO`GPsSW&1U;Oi8=e6xqobaJRL996L0(*oy4^TwK8An>{`n3A{qqCPK zR&M%cmz>KVIVA34pTIOUlxcMckU#C#mArJQU$>X7>^9Karl`m=R}|&(P~*56O1K9l z2%aJS8ms*Wz=D&oyb1Q_{6(^BUkxw;=EADMUrakCM^QO-Slv8^_x~v5j`4kj6CJ}G z1l6NPioA4O;TM~Pz>xZ6T`&WCm5Pl0Q9k|zlUU38Jow1qg^=(i1=iFnXacN00eG;` zwaMq%1sNF7fUjdX6tr!&V=Ux|AjFa|ig9j&du7c73S6rvAx`xkfCb=4<%M!-cd4eq z;U6L>TiUtK%Ul{YY=dWEKd(t&9r0j3vZ{qKD{hgU`2LckcZPQ85PRIW1`AFC`3jhj z!Bf9enEwo$&4w>fis!?5Kd6@PJF^Eu<+>W%DF z!jrf|=Z6II?Jpl#-_0xyR$W$GX#T=?FaBUFyB}mP57K9I|8mk%5YSDyf$nNw$6jOH2H)7D{=8OeTp)ru*1>lhdp+R zCr4VYJbohT(dZ6KUi0!twnxYh)S%}`_n&Lakw?e0t9cesAy8(=H1*`oO`7L*1b?=B|P{2zV_xR4TcRx$CXQt_apIL!eMH69(f|4+Nsy7V}xsBspf+7;6A+) z4c$%hdy99a6^N}iL;pHPvF*jKW8(t*$_lslm+C9^V^LPR)J4+)UUm!`BgU= zhN>UeGIny~7`wB7_uIz>OYU!nj-|She!vLq%(t?c*B)dNKygS3{y2I1iRMC6me=|f z*Ck+iG_Tt1!;0OD`&2gh*iAbE9#C>GdMXwau{p7gJZ4H3l;K&Uh(rp#AR0>ZSc zC$xrS#RUh0cdi{A)R?D?b$$sOsS3EDjxcQ|@`g3JqczAqn1ezC8{0#Zfs{9%a{54{TpJ^9MQT)E8|eq-%pRbdP1-SSgq2=gqv zvjksmKq^iG?|7WRj~1zE&~XI(Hv56@<-JVk*J z6ro?$!wulz1?WCJf-Y|N- zthz2L92sA7wBIEoV zU?v`d{wV*`RxKW;wBZ52SnvdI&-1n#DR+zVG&g!k99oZ%mC0&w7OT3+Ws96przBpP zbd>9uWRu3Pe*FTv;{TuT{#o&1GGfuLWj#N=85&8+TQrrOx|T5HNK16==BQ1PU|vyn zgNe-a&b2OHUi`i)nf~}-I-3EogzJ7=s*>@OG5Rj(0`>XjC$P{2lEIJY>$yH|+st3% zcFa6q=MFo3ymTM51){oMoxuM))*7RIJChheUd5jt=yY>=!8_uLTFRbk7}13WweAG% zVf>1gWElyL&;HvN@aMaJcevv2cxRk0z_xvsw&i^%+5-kfq8ALKPzZCWZ7hd2-aQ=U#^K6f82u_aD=nDIp^<;qC4*O~WPMJOD)Mvmhfr?0Yz;XQ zU=`~BK|8GoM!K?Q^xksG9iz}=G0^hc9;6L)YZ210XgH`B!wtGoK#N8~Pl$#NPPv|A ztXcDvd7R|a=ydFRC9aNatH|8I@RPdyT(l-n)%6ozYZh(56abtIC2(UiH8WD1_U+!m z6_vOG_+u?34*p2B!dI{!m{X6s@~v>;qhFO>kl-jczn#b0O%4|6ntW(22za8YHgYw|E!g;D@I$1&JOUK_ zBrKS5$2}sBm%t}mO6hRP$VfeARv%EGaErMs3TOl|4;fh@f3nUr<`j@QL%!x^swrmI z)%Ya|k={#-lq=8Ci+qnDaW(VZ?OlHg;aM;aY)mNyy|mN z=`uB(_lTSAVxmrYqMRN{>hGd0r!QY>B*&8;IqB=yOD|r9xehW7e*cNyj6AolSuOX> znVZSsunn1;*<<)Eyr0J}m3<;+Jk<+DXb@Nh#dHqak0l^Rp8|$RL`o}fd8f>pPDcbd zlUt(Nu6&h3sQLCVhDY6Ui|P{gAIYMIx`&D%_9%7Qx%A4K#z6io>f`>wPT{mD%t3S? zwwm{EpKGVGC@|--NrT9Y-}&q43{91%VNY>ZCG$*+{pn`-;vuSml8=9l*UYQgb6-eI5qZmtpR*i{>5z zsk=YOfYs{Xf)%AX%DdtYZgdz(X-Dk5;T%Xr?jt8{qDJ!-7=DvArX>DJ<`g^S%S0a$=-B~rA zi2u7Arn)i39U&UO_Q19?^ z4K=S;s2YulmeIW{Z1K|X`YOo5Dwj{8?dG$iuOKdaE7rOeAX2QC}_?w@4M-gplz*mrE`fJ>UTR*Ou<^OmNr$KO#v{=>BX$qAIs`7Z~0=e`kpH z;r66ILkQ!JWYS~5CJ=dmvl+-UWC@{&QY1$*A5 z;0zM)=&iE=YgV4cq92Z({=tXzxZp>(76c4{V=UM?0|~&xpiCv0kNQbBe}Ss$k8IZOO2`j*e>(AhHGCYp@W+zl%WavI{#GBX=>dV zlu_QR@Vo z)`F}b)`X6!mgB8SuzS%J7lyf$ql`Mv&TqR${>WhvV89WxHt-qW8?_Cj2y|=Aj!#m`&Y~r#vnSfG_%Um%j)i zmS6-%gSzAMAMDP?y`)Iop*%A!Fw+Nrb;pmXQxfhhWJ&!wu_lgkS2S@k(VN3feJjMa zNJY_!UGZY9_UfI}^I1vXZ-jZ@OMy!I!H6-*^nSvkR!Q!$*(RvBpwkk;boK zD2(e~dwS+!^{ACW<-fH)(*zydmq=#Wa_Grx6X&to!p8@qZmEzSMehK<%F#8VE0k-V zU4!ef)7JhRJn#6QDOfEcLR|HWr%b;T%F8k`wd4gYQ7eHRpqB{q;MVy?pro?Nb}^4gw=GfPho#%j^)U3MKyQ%%t*EnZOkJ--T==e{x%7_s9zcl&bEt)TL2()0=gh@ zXhLaFz3P~_rU}lQx1+B}`%|F`DGnhF`QmKm z?V)^Wai45uA)%aLW8jSDyj2_;FJUOxg_o-ebCcR<2a7;nlgU)D6kL}5MMs8eXE{Uj|3^se zR=Mx!V5=GG;Z>*FTdJNr!nHoIR&$ZxMh0``M?2R{M3q)KJx1uM5?FwXxDLW1W(F7U zz3zny@mu2=@JndJ#k=2+X=qz<*nvg^QsY@h=!(lqP1cd~L9~abW`k^;oq`&PEWOj-`DxD(_Px^?Qbl{-MTsr$e#9f5vi`tZ?^8o<{Xlp8bLcNmU zN)fC*;itn>LeZ)0Q)dxQhP(c3c{wj?Z96IahhSm7+*z|zxi?;$?2cINZKLLHU!lU; zJNPr~09$IKQao5K84L5gx;JBz-aBoz8f`=H=ZB3jdsBA$_F8qJ9ID9VO31x63M2qK zbd|CxS~RcL*mShh$AJK9q@-*hSI}DBP7=sGDAfy(UQIPl|4-n(A$_Q{BLby0vn)Gg zj617#NOJpnOg5|m3sn@AIm5tP1>iGIsL#X%CYJl63g&{cd1bRB7RIr-+dX{uOZw?u zS)yLRAnO$vK>T@`wqe0}w}Hz9gtLOAx@_sv-+H$@TfC%Lcn2DVJ0{R2VFA9M{fH<0 z__YAQtK;t@Z_eXxM6Fo>S)sbu8A+QuV!L5Mz$dRxkNkJD{buh+4PR^cjZ+-oxwrF} zx?Tw@^nMq@A06Mwc$V>AJ}7IDPCpQSxcG#`zNi5vGenArOoFp10u;J`1$XRapy&>{sdEsFt1ep65{8bEechpkgRk@ zVBHj`xq>>gf5SD4a~8BLI?}cF!&i-27o8LCe|80tsb2St)(5*hyA+0e_+xJMUZ+syz;!P)?I2v-`jc|Jp-tl;^Bl0Z~75k<`s}KrE z-@bqf?>7HF5nYrvYnP}GG7(q&Nv%ME4C!h1Sfr)01eg0yW>c#6g?D`v{eG)~ARHLo zVm5`CK?9^H7TY{}@xI=dBtq*U6|?=bBNc(1NGL|O=A)k-` z8ctQT$bXp?J^tC2n;1?n|NKWc8zUfk;w+Xt`G8dxH*PT`QRB^_D$TzhhilVIIrQkA zj3%VMVMcujF5y$?Wut&#;9D{1%Hg?=Xk~ZbEX_YPg_?RN#V7~5v@#*HFa`L(Y_vdq ziy!!PmLAxR@o0!xY){btBJ#r$M*^sCNEK|_$9bx?73FB3Es~MZ;_|u@qva_rEs6Wy ze$_)W0ed8nAJEW%_l<^y*)9Qo9jmomUWoZOZUA8Q7)cn_o(G_vxiYbk4V?Kq+<+Kp z;7NG5ASR&T0@gt!gLZcjkTV?8l3#XR0xQtv!+9=UueVq&&PED2+1*#OYAe6JO0KWV ze%G(g9SSZp54!I#vJ8pAJtX><-u%HsLK4XdPJknba_EXlKhsL1ccyi9zqZyW;6unr z!L=>0Y*NE{{b>bXfK~qa6MVa?!5!Q?84duROmwr6P*+r0%?VJdr|WckPn_1%kgB@@-^=($a*rsrz1G_@D>e{HyKff|@XsyzhKVlgcm0;DiQ%Vodrto3A9@?^JNfd^u}84FIy1hkOpV&P+(dh7AEMV=S$vMS{b$>iJtb>6r^yj* z4kTVB2(YSEd%A9lTQ@x`I#TT_^(D!CG7!bU)%Gc=Er^*n9p)%66d z9D4O+y`v@WmYccv5D8GTub|z{cT9^&(q4lW>3KW_J`bqC&`WE#Z z&!dVWM}-T3pn;(SXc%ukFB-x=#y;k z{Po;l3v~^?n$z+Fr&>EcGS}U*Rj!R4C!I_P@aH8h9fo#g&RY?!oKkme-6Fl zG54cJcKgAz#pi;~($p4P->C3T$4IUVko?vhRMim|S1?e@`H9{C*!(aQF;=y$;yB9A-sB zhRi;HsBLr~0sEPdGIIaFz=3-*r*t}BWnvr?Rn+ROU*(53;Du(Qu9=gG@aFW4Pl6J4 z`~#)VIR(?^61lWG*>Ndp0TQ0w^E^|hBN@eYXWF$4EueOhuhkI=WV4P4ua6C6@g2YZ zP7bOiPwv0nlxf#~{sV;F?3i~}LSbTr)nAPLgv^D)dK1WQsowRTO&HFE(tD>xtg7mh zXs1cP`=&nMJ2Zkadujkb7+RU4-hB-?-gYettfh~~_msle>O9A^ku&1<92Ux-K`qpU z01`%*{$OMo_hhr=3e}=(lWD_opTjucWEt3>Y}qGW03zNIzEIju6qM2^9|mZg0w$Po zHt#9N4RX!NrDh~aD_GL4gIRUh)Ug$;D-ijGO$4%a)Eyf^g~7kV!BHHJ_)Slkj@;MI zWbG%EWd4vpTc0q^`E^RQ)p$DA;Pz2W9cdWP2yT5aUeDCkA1?A7uXZXGb=`r+h?fm#T%6d z3?U3wV{ckrrl3Laj(^`9`$}|cPf%p*kzs*oV3M%{>!07_>ZYOeNTgo^Xhbf&i@N)q zFXuD4e?$1IS!>QoLWgIH6Z29SGEF&WXXU7t?2=l`N%Q|5zaxvvOpAD27h($@+k}4kc7<>NW3xIZIY-T2@*3LdfIm9fAY=Z}&wIwM zc#QsT8nPJrlItWg=!Qven~5Te(jFWc8P3Y(VERL;|H)>~Rkh#1r=4#Y?Jdr;8WfMY zC%2^Y8__IBND1H{Y3V4uHfUU6Y%W08A_8ch%gBCWI(R9vaH$hiBI|s@^%%N}hQ{y8 z{eQWUjacwmc&pY zGl(-0Ys!Bil6S>!3W)=S#0q&1s#v4+S3I06eC6e9RD*!(NJD-jRf;H&XcF^0e5zJ; zKG4BvU|Y;Bg&PW`QHhz__&1HxLwAj5I64s!9+}VsGaB{{*z;_nPsgG^_07|8>O9YL zxGw4R2W6J!T+GACwQ>9W^L4n!cq55M#Ac?wg+3A4jwM17C*>DR>bkS$_EkqI zubY=+7Xo_8odOjFg`)*SZSW&|ls9)@K^RA1qU>lYxBszdLN2rLYzWv}$kl=He%xdGu7~-Nj;Rzs| zB@tsMoW1V>0p8Ab|Df;B0!u3c6laxtWu2fb)vrU*7KQ|pLUW|AiiFe&SC;v{UmZWZ zt9m^D8j!7SvKd5wET}yH&vY0107uj!Xp5v{u($&0d7#aN&vATxb8+Ml6CH@ky^tF7 zZ7YFn2HD@~y^2R>yumE1@aBb5?I@V~_Q^W+WX!C_=LPcAt?|pCblM1qp2hLOXw7p4 zou%?ukX~w?k#XdmGr*7QPs?Vcradx;6b8p19|MJVgkxCqWEqDz}m$e zWf(zKUlKx&mc7fu!$`f(Q&iVv2Bqd+W6RIe@0cWgNE*k*ctGhM1 zxsR5ugAX786BRi#4|F!(#OJ=4gLN6#k)l5%GbgBXZ~s2Z?7p)Ed;WiHy=6mIT^qGa zgOr5Q64D*g9fHy!-67p2-Q6IiGzds{Nq2X5BS?26@4UR9cklgS{{!?|Yp!#iV~k@s zH{4Y%J-|M{$6fXW_hyS|?bwS-arxcq?A`QWzXawL`?^Jm@T5qds0R(E%Z^BMgeN zJfF~|?=CoKMR^8=yz zZ>-$6s*5wJ{8S%u_9Rnd^|rbg#xm4u8R-$oK6lYJ!4@j{LxmJcOFFijVlE%)F-wzR z@T{Up^wR~!NP+~wTvGv4QxJFk0G(IK%Nr=LwDY(7@17Rm(N7xj@+zsP57lGHE=GFu zU}r@W_8zNb;hwAAKK;wYBqPYjm7r9z5`FA))} zJmC_2fw{}}CS^@TV)5pd<*1IuK|l5o7=K$b1D}g|XQpXhL^T9=Bn)U-3uIP#R)5j` z^kX)HVj%selkr3dEDUf-x7(QUPN`9fdlyI%zln~^^ARZBwUelVaePCLlGvam3nm$@ zjM%)^dY<#Qoa!E_AzMb6>E&QAZ=d0(_44ZX>_KkeP0kdm;Gf!(ZE>^66I7mKW?cv8 zb6xUakAbD84#$LbZwVaFpY`P@lkeVpmMnY=>Gx3%Wv2LI_k2_N9#lbp!XPU^jzIeg zL(&h4gpPaQMsriAX`u51Yq+m&cMXQb|JFKP zVg@@fqe?GW#Q3Gq&miq4@>zxR5X^mQ=8!6HB}Mux$IQ>BfARus0ETnX97HF83nNjN znp+97N8%WyER!vVrB2s%Sul0iF(SGq^dog7`ylxuYRZwiH{luJtmT#yfvdB*F6lLZQWUhyqH7I-u>flPO^3v&$LOUkpOTPJ(Ir z4>cu=>%$E8kl*3cTC+pUf=RWE&5`;bhJ+wt37RFf+ribTZuU37@{(;%1sU(r0or_n zUL6X@{1VHC3=iPcw*$8RI&^}P@$_9=vZaFi4IWPqOl&I3V?XF65h z#`L!qc*%aR=+GXU9Q7LeQ1db!b1NSE0`Okh<`pmI#38f>!-;4hZbO_k)V$A2@p7l_z6dqTCnIiBjzG0zstxU!H=| zUi<^(!j9^y&F;o0y~c)cNXAL`cwVJDy4M#RtS6a6S|K>-Gqd7C=PbY)8n-5@f_sO5L?(Pp1QB$hpamEg zmzxK3(OK6=r|To3eaa4-FErfc5@#dn~g$Gf))rw5 zmC!N!J9wZLnA7Q*$Jl?U$TW7L8w&t3>WY`mlcF+{!_3|EQ`7d9p1(ESeLGC}*{ZMJ*Eq>KZ%T!v-pXb2up7~H{d)yb0u+RAKo-(R>rwNx2X~d@kzs{{Z3~u=rRlGjE zTMrrmu3r$h%(1{ONqU!MrSrB`1~7OHq)C2_)|h-(P@a{Fco1M}etY0_M?Nt2d*Q1m zP5k{dEomg=AeT^nLdBQ3Qeh&Bl(4(9m=Fous z_~C%pywMcyg*Y`NcKLA+fBTPH%g&#pNbjN8iYb19csy%qSC$yHLQYwLA!RZ*k%eVI za^`ohg6A!oF>Xq!@XWrUXmK~t*kz@M*5^YPz+G!Fixf4~ODJ@Q`ViHWQ<*H2y-Pop z75rjJl;WSut6zObUW2tp0R!$G@(P<|vFuTjH_@75y^obz*t@0Gxw?i}iEn#A^H>t) zfkx+-&rXBoE<_xcF~SmvhUp)cmkk1PR0P*cXRi>__jthS`8Wl^qep`iP|OF4pr*c5 zZojIHk@bQxpiK_@(%n%0?^Bjrb%`jKms8pA3kDyVmo}o#5%19NwIq?9UQ0W{JwcFo zG37&=er-M!W1~J*k0Mdeyv5_<#|2h8Yw8KI3hPVEda#cJQhSGuCJKAIQP8ZkgTW2m zEdIZbCV*WEige!E1193y>?6c3<(nA0El9TUd#Z+7-%xd{6`tqSD1QVkS#Q@{?~j(L z8j;PhKq#n7C5Go9Bl#qyropLbCP^1xxL@5{z&IkkA_O{R6mzV91Q{Ih*_R0Vy8JiWnt2cx4%7H=(U(o=LY z?9t9Q!krZ=f_TSkh*F^79uz~e|=kfEm(B!lj;kOo4xeF=#-|* z@qW6ygaM7h{N!#nMe!9KzTexK$+fju5^%DU8*nZECE@TFQP2#V3~VcPEY83ON`SNN zDd<_mgZosAKQ*t?v5c|VD|N3w>_JAX`P=gi7DYn&xJG2MHIuH~7bgMLhSRMtI6p1a z&6Miw{}%Jm1iC7te|nXLVN}g+dqy}X9I$^$*hEb93agXVsZaRLT9D0jT6hpxll#3? zCabv)CpmCcrugT1k)q6QQNa~r`!URuwR7cgORFnDCIpLH)gJH zrJMY5xSb(ZWMNTBq`36RAlKytujZ`D)v6-c-+ljGM?zAEes(%d5iiG3-bVyt5nxx% z`v^-@Kuh~BAu;#DzaZ%?nKNA{^oLu=W?hPUzM`ZY+SE^4ie9+nz%oJCMqWlySbZtf zK}HW|(^sPLmu>sG=muo4P>er1J6_yt4nj9WqKsNkio*_qc|#gsZ3$cvF@Ze{CKyOI z9l@4$l>kRk^jfg_KLBe4C(EV^nkFs`g1E?5^*9{a@&Au|B()KBL@}EW!7g&900W`H zZ3EG3;FaN=+PQU&DvUPn>+l^gOf7SLbmQtaFp_=Ef?Yp(`Ik>)iL2Ye3kpNZC3#V}WsgS|{%z}YwiEXa0KmQFewk2?Wsb7Wi^Hrv8jPYCWex=$9b$+2FRqmG( z^S~ft(q^n3DZzyYiBgkmBsyW_sP1;OR|GHkVQo3Me!5+J`+GGxuXhyF5RU$xh%T?~ z{j^0(THoDDnZY`<+!q(qfd$lNKwSH40n%s6DekumIHq2n z%6!nWNy=pWut(sNEB}F8X{MW;wLBsewlU%1LvD%ka4I_)@^|Wb5}M`*{htZ#fQ~8g z1=4+2GZP?d2hl#oz7VtM-@vxG-Qc;J<1Su(znsHs@zUAzD4yUMy|YTPp5D+hHV+x~ zqxSNl-a87jGRLZ>Jo2!1YM(^yW*9j}vg@0H^V7+@;McOz8tMr!LIpK#ej0Eoy8xUn zWB#}4>%wf-JHS}}^#@xTT(N`x#6M!v2Qw4FW7P*YQZr#!O`dxVsNRgaf2R=os%084 zpn+Hq6$&9U30d=LdrK^Ri=?9>?Uz}o`jto66-S?MfS}8cT)qR!lyY~_L z#o}lP`AWoCNpg`_pj- zsbbVg069~Up`tEooPA-WKsG1tC_fMkHN1E|^}(hcnCDHV{T+i$U{F=ibW_-%(?fMr zaOT~s?lsZyF%qkkILaqg_De{Rsj{eaY@v~Xl4fCo`zR#QAO|WI_}IFfFNt$0XHY!4 zoUL(Zz4!ChtUW4@rySqXX)tc^^7h>&7}t-PW23)@*eBH_KPK;mzTe5PvU1QXv4B5^ z$m|>>Gh{8JUw8N^7zzbow^2o~r~j|a-j&5zQ8aCxK18EJntP~YlXbmuHI;(6D2&4$x|Pq5`yyye@<2vdlJ2@FBL_rUcx?Y_ zh)I0@0`23~x{76(Bc6Q_!1*+t=wUQ2$xd>tDE95=VRUhTJHWe465qUR zq)x%SF&l`#(ZxKw#vTesa)Rw-z3vr8JMoQJtExC$GK@{epx+lWrYNa=T^kzc_RrNP zn})3*hqtImQe*mP>I8RL^13lflP=y&b9X>tM}i{Sn)gl3usF3nda2U-$tuyH%Ji#Q_##N`zMynOO3+084=4WHtATh( z>XPE_8{a04@rXla!MB;-tM8$kwbs4=0)b0Z3~t>1fU}T@rt%Vs4Gpb@&P!rQHst`v z{H8o3{|0k!=bYcnK zIa9vqtduo*}=o1_Mqyj#XXLtq076DM4jbR5U-+Fw|M;)v-+3|H&qmSXORnYwI0(mRSv&ql+w_VCc=xu=sIvtS zKZvK0LR^-J{`%F{Z+6bcIEV}$tw?s`;?%GxskZrdi$am}m-4(6&<}_ElkZueE9yqj zd4$O0jwN+iNIwz7T9eD-&pPs_58s4|AaX7ulRJ!_ldKSK_R z+<*VY%_-ACrC%4XF7c#v#jeaTt)K+RZAyE;Q)vO;^+0%WQ^<{y0gphxqk@a!*5q&r zKG27+5Uw3GafF@JM7OW7?`oYpoE8=kUPj&eFn0(nEb)nY#PsA-@#tKyV9rN2^-!V3 zZVIq}*}yCM^R25ONL2S8YyY!7d643p++Py^V$c1tDK%k!RLL1(8s-{nG}5vF_EWfWr*?un3YwYwn;J_FN?v;xUrhC8z4G7e2+p z7CCt}LCA#BL(zI$IAPH30|zGCJpsV=Tx%yhBYoA9wk zxqWF1->tP~I?VxkO@=Td8~8ttME$M=Lqcx+P8*h*L+C?pqH{d-!`z5whXH@5ia@;N zkIe!q7&W@R9fzjx%wL!~?(GfEO#!8YVEVoQu$Hd$vD1pcVtt&HjnqY?C9dg}Nvko- zysd=(oa^aZ`ID&;2|{9TP`yft`%_F~&eYcrXo{XbRj+}jNcXAUYAHFrRitCV#web; z?$BeS0-k}r!wbSBmpho4hoxJ_&B9=}nePC?K5@8myY06_;eRd{0;~rOm;Eo4Z9#lJ+$K%b}Ed&pqI zeZiw&>DYq*CsxnA>SBqFOfA<0ie(+#ReXWS?&mvZ%cpHC5#O}3ulg~zM2_X$IE|SD z`g65%NAZwmq5lp>Ka+}`lP`>=Fu!bDox7wj>Z6E>jy5Hij4!!Mrl1ANU$6$iFyv@* zwA5`&S(k^X@avoa5j~9O{F0!$umBCghDERu*+0l@T zj6uC{a9kAe_c|yL5zV47_QMtq^58%15%PAlq8J*nW)zW{6^G%Yrihv<;c3m zx)-BL-~xk(fp6EDwaRUGEWaoNUe)knocQeW(5C4Ud&yrJ{wfltJd zu<_>rqt+C1*VBK&c_p-UnYT?`&U6Cr7ktJ;2kwq=%b-tkyO}sw7V(;4T@Qnen3cQu zmihCCbUTsh6KAJL<1#X*7%Ic@W|g9dY_e;ClKR77pLe^ndN=eWoC2OnV)%Vo&8CD zRV<*72iTx9Bhd6d;=7O&qyQK1(gwx-V5K+GYl!6}m-kXPRx7=rA&00rFFq}TpD&B2 zNcOsE?4saWa;W}qV|st`pWbANm^_mM$4iwf(&HBj+_7s% zGrgP$jVjxA#zZyav2cvy(`*+Q2Ie$i^Nrs;WB@f3Lqm#-bHHV2@k(jvxO!yP8C#+E zv&!<9bnB6Ke*h`0>jm{^Egtfl@36ODPU|eBIqv^Q3rjy=Dt5{+9V-1rUDobu7AeNq zi=w!-uLYJorwtisjMP<2-<2yN6?iGiK7o|xUs5ie0mE7HDTVRfZtX%!sY)Kc$mfc> zqV(;Gxh^*uTFlPDluSP+VgY*NKd?ECE+0Q8Ip3gz;Ykizi%*Lu82S=}F!})55bpMU zAB2V0ZYo^6c_mTX$>2TYTb}%$&%E%6^!+f`FRI(c*bt3#Zvo^-;1eRXYqJXqaEsRp z)_ryurcYsLYFzme_T2z&u|+?!68WzIUT3eLI{2&Kmwnx+bBl;toT+6>cmZZp&#&ox z{;H*%-%3F9n4^1}9gbvG4P%X+&MPo245P1F{1}&p($PzNHplR`PIqyG>R~^GX58?e zu4Kf@%r!6ZLF$p^OLxkd&65sZ7alE6mgbvMrnG^|G)ZZ$vpc z+~{UKZR-_>>-*1(wTz`(d=h3=ru1>e0yTZTwkhGR3pIvQ)D~uAsuh_d)R94R687Ub zk}7TgaFL~7bkiZ&8S}dQ>AfQlQ?m{82B1tSl7pWQZry299g8oxU8AhCGZI>45|455 z0{!lI(C&p^W~EY%aGoNC7q{MxsKKB%Y zYRLe^jD6@LU&p!7T4oXS7l>B2;zC-yNb~qVGeQE(+W#w_2}u60c&3%Ri<8(2{fXaD z{&Jjoe$H}9tPN^vG1}tg@YZ^H7U#bl!TQFUejud|I{RlF<#j2erHZ^3!bY$ke4AYK$xIv?|3UpF2vN zt=1(lIg~8JNNLmt=eLDwLnCA2qu@(1Fmb z#NKN|{AZ2JA=&fg916BTV#1QH8qLGLF|!4|K4q-p)a_sdMNMzHcP={5`)0!lA*Z3m zaLF&Sb7R%#DC?KA$Iu@{UICg2q&7$8-?j-`?BBMj#~XpcZAMZ@shY)eis||wkM`K! zpshTw+zD}BzRs8U!Assojo`9=E(!VGBd56ahY(E6l6<1lN_bp=(w4bQKbgQVJ%kTlKh+H!9qqAn0Cs~;+k z5cwQ5rC2%;w3>!&^DSKN@EHR-L^BGwm%TBMQ!uLry4~B#E&?3>XlVKfo;YgPk(Yqg$F-B6Z#HQyFq5N7vxm1D6f&1 zOj@&qZ3Jv%t&~Eq0I6VO9R@WJ?Q7o%j3C|SivSN4i0$(=bp_yEAA&c-gFWGfW*AT*rx^(<2B8_O(_DF5Wk78@VpJ=>M`{ue{k2 zm9?n`P_jGM{QXjxkG?7y#mb``k-369)s;P|r~zOB!VVqzy{iDTOS-=dEwtLkf&&(b zEmQO-X4%Fc19*>4BdLY4i3GnaV>x4X?Nzn#VR3~)@9KWW9x3EwdR+m%*ab?pI*Y*J zaBm&6gg2Ew)}PGrdZ#;4c*Q2=g2%)Cqgs@IYvWtAJFJyJuPsB%c=5_(zSgNNKDYHb z|2*a_4e|cDiE22%Iid})78F4$o=Ic8*w94qqJ&%r2`+=G0$txwGbPqc=KO8-@}$dY z9bUO<{>XL3!y>#6$WYNw=&Nx*#%1>46?URH8{BDZiK%mvB{Y0iX+&+9I0SPMJN@T>SMhP=xr5Tz$D^b5C^uztMVQCC zPTok06zY)LgQ$xTF`ikcjiARiHFb50@{_@kdi|vo{z~Ukg;kZb-7~Q&-2#yeeEhYU zUp)O6z76;v%wW#G{C_LQ)7Edfm;RcM4H+UGbrN#nHJL>wq}$o!b>N)e^#jEIdC^2d zht?Yf>ac&uJ*_&wmiC7pZP>Y)m+J`J`du%`dGlj28Wjp-5u*9LNA(oQILi3I+#q_M zCM@Z$_gv&BKvLDA$yzJN51v3Wt&VKS@I7mwzupb&)zR2l0;DRrqLU+`_Ggb53$)35$ScNH9`RR8i$adIrMZc5)(h|f=6KP5DNK}+ z*QhsW`Y9xG*&(rmbe!^*Rkh)7A;k=bAA=;aRV1+E9Rz;#-($_6Z9}h%0PU0QlWf04 zV*HnEr5;VRV+=^Is@xV9DvVm-;=oXrCMMj>YY{zq_5s;clXgJ&t3YqJV15mfY}yX~ zQ;_A<7coELCWs$z1^LGc+n0lMfpS*grcqVq#ou^9!=a7wp^)t?SJ+LCFB^X$vYK*i z;V?Gqc@nSn-TJlP69{>gic3U)Gf&ob+HyBi-T1k!O*Td7G5{%I!OQybc_<(QBIJ@8 zRm>QQlPB?0nQ_2?wZ4vlR{TuJ62F#KpdLBuyuP&>Xb-2q#L7Y{EI41ZTyuGJcRR(8 zTa(c)Y?2de5rr?E9+Dr5R1fT8%fkIxXXuUx$aj1PynohA5pLl^ATx9OF8=3bw-)1N z*8e(TH_GPj!!N$~8>tR-H90eF&IEXw!_OwF_Uo4S`OLB2dD396XV~13J{^By`yt(W zBVjpBBId2f{P0~yINJvS`e^h;=)~FUEEcH#o0NOFh-8edh?!m&-(&oQXaxo!c~-=+ zMazp*1%&_UA(&d?c9Q-fDH4FRF#g1*`= <5EV59KKc2OpWZgbY_5xg?0D& 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

mPee1R>y7S?WQ20s5S7(XzsrsIO9L(qWb8 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 literal 2132 zcmV-a2&?xWiwFoSe(_xb17u-zVJ>QOZ*BnXTU&FZMizeeuVC4iq{=X$3liih<=NRx z5_?jyGMgIPMK#b!z2=st@mO*Bzwc>oq7m{SYsNONt+Gqf>DzbiN2t%;ktE4%onYCL zWG{B*V@|k1LB=U}@Buy&kB_Daag7*Ou8tkSM_kUys@KAaf;~;=GYm{ z@bPBIjf0r-!~Ushj_-`+#+Zjwmy(1P2<63!q!RqCfgh>lUCK}Uhp>vI$O*9b4kMOP z0b~OvOpH*Nv-!3Z;})ZpE((rna+Y|AVb4a44~{h5R5Vl3jfG}f+Q^#BRBb-{RBU&D z#Q*P)j_&#^H$+LQFdX0zGrG3KkB?BcxL!~UVvG_eV>tZ{(^HfPqgN3+ zBXhYgVuph1%*IACBOyLP2{%x$+loweuFXH~?R}Mrby`gi<82=M7~^&0$R|q+d;mhn z-nLq-7H!nYNZ_4iAy7?Co9U)GnoedD%{29<*8^AYVj3c5vA_9Qe=JVKSdu&W`wGfb zH^=^brYYXs&=p-0u4q1*PUh~^H>cxA3%_KepU@3!s;fXdTmxXH zF&bN=k)@AR!#u>&Hxc@P;QS@ty2Ew`+4Luro?{%H#f;=z^1Qk;gY^ppP4SF0)f|rw z5Kk@xC4mfsX=L@%{NBd413KjYincV@H zcmoQv0UBJ?sv*B3M`);Frz0e*IKnUA4?MKCW8eOa@%5m<+GOV!5&St@5*PQYvQ{YYZ9j<7^F(_QcNP&gMDT|`gME6J zcs&neJCv}~Ib1l3|DM(^hF(}csPTFv&5yQGSRfdZQ`F!SOkL0xS`N&s2UXT}qJBl* z{cxeTnMR@^CXhiw&fjbmg1c}BF}JywfOrs3VLMU3B7YW@vD2Ub%231zTOaVq@Ttu# zz0O|#Ba0d>L$`yhE&#Wm1w)MWfIPryIz;IC_p>1urHA?C6P5j?Ni%*Qc|g`t+4JCV z=Xi&cU<$n8f`4WF2~XjY1AyK865Vs=Lw;NLMWVctTOA4S_@&vivMpxwfLol#f_xae zaTxM%-`f|qA8s#dU)q&tk7_fjZXt`?^}F6YvGlPzo*#1Mz7W4P0)fC+|Jbtek zDM;5eWj>voj$?W=*Kodie^!2UA-PF!$w^{oPr=0=*RoqpQw0m>=mvWqod05%onnU6 z0$R~A^z-?LGqvDZ*r8i-N9|^sMnhS}@14*#mW7eXA19a3>BJMOo0Dy7eb+}EsD3gL zslqLTt_3Ym0eZ)?L2&|<4svH}TC4M|>3}Q3(pEE3r!Ly9Ty53xeIZJ%$Z{3HKl?EV zHX-Atu)7Tb@&bSQ$-i+`Z!hIMfCVU8X8H3spj;PY_dxeazl54fUivXf0{kEB{6g59>3F7&4e7gIep;OVdMpLx8cYAi?sfdVbh3ivg5S(c zRa3|2WU9_g=^Xipl5*A8Z;L5~P_x;PY)xv#i=qc_TSZ?`#Y9)NgW7~Vl&+i@QO`2m zkuk>FSI!mn{vyLq7eN}Kp(_>~ixHz08g@8#oC8mVIOXBrP=td8_sFzS2!Vm0BDy3| zUDq_3P57F6Bi;+NiEWp1-Z7VBTvFn3&n_6bE$gmz`T7}NCv$kSf;S^hA^Cc9f{~*c zzG7&|RVHXYRh-#OSH@_Ly~%9qf?^Ava~$uBXx4inuMeT>_B>wDo#g#(9ACX(Goa=K z8<-KxI`AZl(-n7d3ijF7X@Wp}TV2@=Th==DlNXEN^_zA^Lm3$h%>d!>=%pFPr*?7q zJBEBqw-3t)7jb*5nKhbOQwW5!@h5p#M228oS%1%n{BUX2bS9{-#)nl`dlZMQ>Z(*` zci~hflLsoMIx=lZ=S$%Z1U@sSUnTR@s>$896!-h+4;nnSQT55f{?yVTnVFN89R3GK KmDJdwK>z@%VJ_4F diff --git a/x-pack/test/functional/es_archives/reporting/nanos/data.json.gz b/x-pack/test/functional/es_archives/reporting/nanos/data.json.gz index d0531c76077366d510adfa1723623ccac2d1ae36..2811c495aae2d2f7e9dd330661fd9f5f76850ef4 100644 GIT binary patch literal 863 zcmV-l1EBmLiwFo|YCT>617u-zVJ>QOZ*Bm^R$Xt}Fcf{~S44Rx$PUmnd8^b`+oV!y zpgs%`GRaNInh)kUY*od7pFffimv#*m+oT|pWBdBtbA9jibI&kL_Ou1lGt40O&AtG3 zBq;^*%s=>N9Eedr&%!wJE(d6UtR zwR~UOF)4&VA@iZ&Hs%$&Y=&zQDw+*mZUe#~SP>>hZG>G5ITmtfHulC2e+Jlgzp3r2 z%^F)Pp(uy;y?w9u++AuZtF@6G;;^+IQJ&ZlQ21-W1)7WNlX1ql?4##tmWC}texmb`g2ami6X zFEhq5#NP{_##_009A^{)Vg*VUE#KU?hqtM1<)m1rprSJiX5S2O)V;TiN$@ zhC-CCB-Pyi!n5#m3OdiMOxHjqb_$&ue8H!NI}?)UOJ~#ub?NGXQ?)x2S;eqZkkyR; z5o48aZITV5QEaDSnFU&W_-pr z^JiJr=E9UCFBaYOG+HJaKThbA)jDy8#Y*MGl7JJf<+ z)j;Ffus=vr-3&Hyv`P4nT_wpOD|ag12jE8u^hweq!SYeYh_sFX#7Badoq&+#x$ zm}qId8ab?G@JZroriE-lB4oQhQOZ*Bm^R#9)GI1qmCui&`XfNT;<;jPkcb$8OH z(k0r5OQOhufp8^|Gp2V{mH&QY8xp*2x1`G5N<@Kg?D03>cxO zB!Nd(G!l8n5B$s%X|4AxhA4rQHHA>)q^V5cA8B?xm+|_u3_PYdDO$*&I^fP{vT>phb(Wj^=K9&*Pdy4g3)#d%+tRolJ36 zR9r6hGa;LFGq!uS1nQXQd!ZTH^KD*R_&i}eRvW#gR{P1AmDg-jKyn96G~6KBqlp7c zwo_r=wL-oKw9AH$=mP(#Zn2OA zo7f}7VO}_KD232rINgDi5+E!Nu0uF`&vYWRG`}l#;E-_c(Z~<*aj6$xSZXD!vu8p8 zFQY->ejp*nDrR2N9E#+w;yWh3u)Xy6ytJhbOFP21Ji&hrtV>o__0m2Z`URloOP%cn z4wt)JO<2o`qoqq-QoCwW8+iv2R|^Q8X;PiZn~?x3z& zHc-w7c>25I|3`5vqO1O)Byv%x!&hnb@`Ct&OY-e$iLHtMf!3tE08DoSZW}Kmc(LPc z<4-Pp+i0C5n2@ngChD5;FL=$o)9I)P{%G(|H_mc-fkE@%A*p2DI6gW_+^k!JS~P)|Q$H;$3-K zaAmYjM(^4$g>5e6a-;{ns)51t$o?cr+Zk;0Y+K+@+!n>DDj#*ePrzRd@F(3tbgxTW zoe>2qvql{vh&*W90r501guK$Cg*-2m$iG86?T(&v@`et3dFcgSS6mj`;vMa!nmwIY zuN^G&&$Ic=`gA-0Y)x;c_p`p_kH_6l-|q7D<`{Y!c%D0^Hy1t)=!+WH$K{*#t)$ZQ ze1}kc=G2QQiN@p Date: Wed, 26 Feb 2020 13:20:24 +0300 Subject: [PATCH 082/123] Fix TS for vis_type_table (#58347) * Remove eslint overrides for vis_type_table * Fix TS for vis_type_table Co-authored-by: Elastic Machine --- .eslintrc.js | 6 ------ .../vis_type_table/public/components/table_vis_options.tsx | 6 +++--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 9b00135df5bac..087d6276cd33f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -82,12 +82,6 @@ module.exports = { 'react-hooks/exhaustive-deps': 'off', }, }, - { - files: ['src/legacy/core_plugins/vis_type_table/**/*.{js,ts,tsx}'], - rules: { - 'react-hooks/exhaustive-deps': 'off', - }, - }, { files: [ 'src/legacy/core_plugins/vis_default_editor/public/components/controls/**/*.{ts,tsx}', diff --git a/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx b/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx index 5729618b6ae07..8cc0ca2456867 100644 --- a/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx +++ b/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx @@ -47,14 +47,14 @@ function TableOptions({ .filter(col => get(col.aggConfig.type.getFormat(col.aggConfig), 'type.id') === 'number') .map(({ name }) => ({ value: name, text: name })), ], - [aggs, stateParams.percentageCol, stateParams.dimensions] + [aggs] ); const isPerPageValid = stateParams.perPage === '' || stateParams.perPage > 0; useEffect(() => { setValidity(isPerPageValid); - }, [isPerPageValid]); + }, [isPerPageValid, setValidity]); useEffect(() => { if ( @@ -64,7 +64,7 @@ function TableOptions({ ) { setValue('percentageCol', percentageColumns[0].value); } - }, [percentageColumns, stateParams.percentageCol]); + }, [percentageColumns, stateParams.percentageCol, setValidity, setValue]); return ( From dfcd4d1e93d4bc49193ea1a9902fcf916105028e Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Wed, 26 Feb 2020 11:34:11 +0100 Subject: [PATCH 083/123] Functional tests: Fix saved object management button click retry (#58218) --- test/functional/services/saved_query_management_component.ts | 5 ++++- .../apps/discover/feature_controls/discover_security.ts | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/test/functional/services/saved_query_management_component.ts b/test/functional/services/saved_query_management_component.ts index 9f0a8ded649b2..b94558c209e6a 100644 --- a/test/functional/services/saved_query_management_component.ts +++ b/test/functional/services/saved_query_management_component.ts @@ -24,6 +24,7 @@ export function SavedQueryManagementComponentProvider({ getService }: FtrProvide const testSubjects = getService('testSubjects'); const queryBar = getService('queryBar'); const retry = getService('retry'); + const config = getService('config'); class SavedQueryManagementComponent { public async getCurrentlyLoadedQueryID() { @@ -177,7 +178,9 @@ export function SavedQueryManagementComponentProvider({ getService }: FtrProvide await retry.try(async () => { await testSubjects.click('saved-query-management-save-button'); - await testSubjects.existOrFail('saveQueryForm'); + await testSubjects.existOrFail('saveQueryForm', { + timeout: config.get('timeouts.waitForExists'), + }); }); } diff --git a/x-pack/test/functional/apps/discover/feature_controls/discover_security.ts b/x-pack/test/functional/apps/discover/feature_controls/discover_security.ts index 87ae5231d1031..1dd069bb907d1 100644 --- a/x-pack/test/functional/apps/discover/feature_controls/discover_security.ts +++ b/x-pack/test/functional/apps/discover/feature_controls/discover_security.ts @@ -28,8 +28,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.timePicker.setDefaultAbsoluteRange(); } - // FLAKY: https://github.com/elastic/kibana/issues/45348 - describe.skip('security', () => { + describe('security', () => { before(async () => { await esArchiver.load('discover/feature_controls/security'); await esArchiver.loadIfNeeded('logstash_functional'); From 08e27d08e9ca5662d1b9b3601d8ff627daa8fcc1 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Wed, 26 Feb 2020 11:34:53 +0100 Subject: [PATCH 084/123] refresh once to make sure everything is fetched (#58225) --- test/functional/apps/dashboard/dashboard_filtering.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/functional/apps/dashboard/dashboard_filtering.js b/test/functional/apps/dashboard/dashboard_filtering.js index 1cb9f1490d442..ec8a48ca74911 100644 --- a/test/functional/apps/dashboard/dashboard_filtering.js +++ b/test/functional/apps/dashboard/dashboard_filtering.js @@ -63,6 +63,10 @@ export default function({ getService, getPageObjects }) { await filterBar.addFilter('bytes', 'is', '12345678'); await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.dashboard.waitForRenderComplete(); + // first round of requests sometimes times out, refresh all visualizations to fetch again + await queryBar.clickQuerySubmitButton(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.waitForRenderComplete(); }); it('filters on pie charts', async () => { From 3b1921163c10acd03ba116b9d4fbceb427c01633 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Wed, 26 Feb 2020 12:05:47 +0100 Subject: [PATCH 085/123] satisfy proptype check (#58538) --- .../kibana/public/discover/np_ready/angular/discover.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js index bf5049cd976a3..1ac54ad5dabee 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js @@ -556,8 +556,9 @@ function discoverController( $scope.opts = { // number of records to fetch, then paginate through sampleSize: config.get('discover:sampleSize'), - timefield: - indexPatternsUtils.isDefault($scope.indexPattern) && $scope.indexPattern.timeFieldName, + timefield: indexPatternsUtils.isDefault($scope.indexPattern) + ? $scope.indexPattern.timeFieldName + : undefined, savedSearch: savedSearch, indexPatternList: $route.current.locals.savedObjects.ip.list, }; From 342e50183d74774e36c275b429cd9afc54d45508 Mon Sep 17 00:00:00 2001 From: Uladzislau Lasitsa Date: Wed, 26 Feb 2020 16:04:58 +0300 Subject: [PATCH 086/123] =?UTF-8?q?Converted=20brush=20event=20to=20TS.=20?= =?UTF-8?q?Migrated=20tests=20to=20"jest"=20way=20and=20optimiz=E2=80=A6?= =?UTF-8?q?=20(#58206)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Converted brush event to TS. Migrated tests to "jest" way and optimiz * Removed unused definition in interface. Revert changes related to import deserializeAggConfig. Co-authored-by: Alexey Antonov Co-authored-by: Elastic Machine --- .../public/actions/filters/brush_event.js | 71 ------ .../actions/filters/brush_event.test.js | 199 ----------------- .../actions/filters/brush_event.test.ts | 208 ++++++++++++++++++ .../public/actions/filters/brush_event.ts | 80 +++++++ .../public/actions/select_range_action.ts | 21 +- 5 files changed, 296 insertions(+), 283 deletions(-) delete mode 100644 src/legacy/core_plugins/data/public/actions/filters/brush_event.js delete mode 100644 src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js create mode 100644 src/legacy/core_plugins/data/public/actions/filters/brush_event.test.ts create mode 100644 src/legacy/core_plugins/data/public/actions/filters/brush_event.ts diff --git a/src/legacy/core_plugins/data/public/actions/filters/brush_event.js b/src/legacy/core_plugins/data/public/actions/filters/brush_event.js deleted file mode 100644 index 67711bd4599a2..0000000000000 --- a/src/legacy/core_plugins/data/public/actions/filters/brush_event.js +++ /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 _ from 'lodash'; -import moment from 'moment'; -import { esFilters } from '../../../../../../plugins/data/public'; -import { deserializeAggConfig } from '../../search/expressions/utils'; - -export async function onBrushEvent(event, getIndexPatterns) { - const isNumber = event.data.ordered; - const isDate = isNumber && event.data.ordered.date; - - const xRaw = _.get(event.data, 'series[0].values[0].xRaw'); - if (!xRaw) return []; - const column = xRaw.table.columns[xRaw.column]; - if (!column) return []; - if (!column.meta) return []; - const indexPattern = await getIndexPatterns().get(column.meta.indexPatternId); - const aggConfig = deserializeAggConfig({ - ...column.meta, - indexPattern, - }); - const field = aggConfig.params.field; - if (!field) return []; - - if (event.range.length <= 1) return []; - - const min = event.range[0]; - const max = event.range[event.range.length - 1]; - if (min === max) return []; - - let range; - - if (isDate) { - range = { - gte: moment(min).toISOString(), - lt: moment(max).toISOString(), - format: 'strict_date_optional_time', - }; - } else { - range = { - gte: min, - lt: max, - }; - } - - const newFilter = esFilters.buildRangeFilter( - field, - range, - indexPattern, - event.data.xAxisFormatter - ); - - return [newFilter]; -} diff --git a/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js b/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js deleted file mode 100644 index 743f6caee4edd..0000000000000 --- a/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.js +++ /dev/null @@ -1,199 +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 _ from 'lodash'; -import moment from 'moment'; -import expect from '@kbn/expect'; - -jest.mock('../../search/aggs', () => ({ - AggConfigs: function AggConfigs() { - return { - createAggConfig: ({ params }) => ({ - params, - getIndexPattern: () => ({ - timeFieldName: 'time', - }), - }), - }; - }, -})); - -import { onBrushEvent } from './brush_event'; - -describe('brushEvent', () => { - const DAY_IN_MS = 24 * 60 * 60 * 1000; - const JAN_01_2014 = 1388559600000; - - const aggConfigs = [ - { - params: {}, - getIndexPattern: () => ({ - timeFieldName: 'time', - }), - }, - ]; - - const baseEvent = { - data: { - fieldFormatter: _.constant({}), - series: [ - { - values: [ - { - xRaw: { - column: 0, - table: { - columns: [ - { - id: '1', - meta: { - type: 'histogram', - indexPatternId: 'indexPatternId', - aggConfigParams: aggConfigs[0].params, - }, - }, - ], - }, - }, - }, - ], - }, - ], - }, - }; - - beforeEach(() => { - baseEvent.data.indexPattern = { - id: 'logstash-*', - timeFieldName: 'time', - }; - }); - - test('should be a function', () => { - expect(onBrushEvent).to.be.a(Function); - }); - - test('ignores event when data.xAxisField not provided', async () => { - const event = _.cloneDeep(baseEvent); - const filters = await onBrushEvent(event, () => ({ - get: () => baseEvent.data.indexPattern, - })); - expect(filters.length).to.equal(0); - }); - - describe('handles an event when the x-axis field is a date field', () => { - describe('date field is index pattern timefield', () => { - let dateEvent; - const dateField = { - name: 'time', - type: 'date', - }; - - beforeEach(() => { - aggConfigs[0].params.field = dateField; - dateEvent = _.cloneDeep(baseEvent); - dateEvent.data.ordered = { date: true }; - }); - - test('by ignoring the event when range spans zero time', async () => { - const event = _.cloneDeep(dateEvent); - event.range = [JAN_01_2014, JAN_01_2014]; - const filters = await onBrushEvent(event, () => ({ - get: () => dateEvent.data.indexPattern, - })); - expect(filters.length).to.equal(0); - }); - - test('by updating the timefilter', async () => { - const event = _.cloneDeep(dateEvent); - event.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS]; - const filters = await onBrushEvent(event, () => ({ - get: async () => dateEvent.data.indexPattern, - })); - expect(filters[0].range.time.gte).to.be(new Date(JAN_01_2014).toISOString()); - // Set to a baseline timezone for comparison. - expect(filters[0].range.time.lt).to.be(new Date(JAN_01_2014 + DAY_IN_MS).toISOString()); - }); - }); - - describe('date field is not index pattern timefield', () => { - let dateEvent; - const dateField = { - name: 'anotherTimeField', - type: 'date', - }; - - beforeEach(() => { - aggConfigs[0].params.field = dateField; - dateEvent = _.cloneDeep(baseEvent); - dateEvent.data.ordered = { date: true }; - }); - - test('creates a new range filter', async () => { - const event = _.cloneDeep(dateEvent); - const rangeBegin = JAN_01_2014; - const rangeEnd = rangeBegin + DAY_IN_MS; - event.range = [rangeBegin, rangeEnd]; - const filters = await onBrushEvent(event, () => ({ - get: () => dateEvent.data.indexPattern, - })); - expect(filters.length).to.equal(1); - expect(filters[0].range.anotherTimeField.gte).to.equal(moment(rangeBegin).toISOString()); - expect(filters[0].range.anotherTimeField.lt).to.equal(moment(rangeEnd).toISOString()); - expect(filters[0].range.anotherTimeField).to.have.property('format'); - expect(filters[0].range.anotherTimeField.format).to.equal('strict_date_optional_time'); - }); - }); - }); - - describe('handles an event when the x-axis field is a number', () => { - let numberEvent; - const numberField = { - name: 'numberField', - type: 'number', - }; - - beforeEach(() => { - aggConfigs[0].params.field = numberField; - numberEvent = _.cloneDeep(baseEvent); - numberEvent.data.ordered = { date: false }; - }); - - test('by ignoring the event when range does not span at least 2 values', async () => { - const event = _.cloneDeep(numberEvent); - event.range = [1]; - const filters = await onBrushEvent(event, () => ({ - get: () => numberEvent.data.indexPattern, - })); - expect(filters.length).to.equal(0); - }); - - test('by creating a new filter', async () => { - const event = _.cloneDeep(numberEvent); - event.range = [1, 2, 3, 4]; - const filters = await onBrushEvent(event, () => ({ - get: () => numberEvent.data.indexPattern, - })); - expect(filters.length).to.equal(1); - expect(filters[0].range.numberField.gte).to.equal(1); - expect(filters[0].range.numberField.lt).to.equal(4); - expect(filters[0].range.numberField).not.to.have.property('format'); - }); - }); -}); diff --git a/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.ts b/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.ts new file mode 100644 index 0000000000000..0e18c7c707fa3 --- /dev/null +++ b/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.ts @@ -0,0 +1,208 @@ +/* + * 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 moment from 'moment'; + +jest.mock('../../search/aggs', () => ({ + AggConfigs: function AggConfigs() { + return { + createAggConfig: ({ params }: Record) => ({ + params, + getIndexPattern: () => ({ + timeFieldName: 'time', + }), + }), + }; + }, +})); + +jest.mock('../../../../../../plugins/data/public/services', () => ({ + getIndexPatterns: () => { + return { + get: async () => { + return { + id: 'logstash-*', + timeFieldName: 'time', + }; + }, + }; + }, +})); + +import { onBrushEvent, BrushEvent } from './brush_event'; + +describe('brushEvent', () => { + const DAY_IN_MS = 24 * 60 * 60 * 1000; + const JAN_01_2014 = 1388559600000; + let baseEvent: BrushEvent; + + const aggConfigs = [ + { + params: { + field: {}, + }, + getIndexPattern: () => ({ + timeFieldName: 'time', + }), + }, + ]; + + beforeEach(() => { + baseEvent = { + data: { + ordered: { + date: false, + }, + series: [ + { + values: [ + { + xRaw: { + column: 0, + table: { + columns: [ + { + id: '1', + meta: { + type: 'histogram', + indexPatternId: 'indexPatternId', + aggConfigParams: aggConfigs[0].params, + }, + }, + ], + }, + }, + }, + ], + }, + ], + }, + range: [], + }; + }); + + test('should be a function', () => { + expect(typeof onBrushEvent).toBe('function'); + }); + + test('ignores event when data.xAxisField not provided', async () => { + const filter = await onBrushEvent(baseEvent); + expect(filter).toBeUndefined(); + }); + + describe('handles an event when the x-axis field is a date field', () => { + describe('date field is index pattern timefield', () => { + beforeEach(() => { + aggConfigs[0].params.field = { + name: 'time', + type: 'date', + }; + baseEvent.data.ordered = { date: true }; + }); + + afterAll(() => { + baseEvent.range = []; + baseEvent.data.ordered = { date: false }; + }); + + test('by ignoring the event when range spans zero time', async () => { + baseEvent.range = [JAN_01_2014, JAN_01_2014]; + const filter = await onBrushEvent(baseEvent); + expect(filter).toBeUndefined(); + }); + + test('by updating the timefilter', async () => { + baseEvent.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS]; + const filter = await onBrushEvent(baseEvent); + expect(filter).toBeDefined(); + + if (filter) { + expect(filter.range.time.gte).toBe(new Date(JAN_01_2014).toISOString()); + // Set to a baseline timezone for comparison. + expect(filter.range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString()); + } + }); + }); + + describe('date field is not index pattern timefield', () => { + beforeEach(() => { + aggConfigs[0].params.field = { + name: 'anotherTimeField', + type: 'date', + }; + baseEvent.data.ordered = { date: true }; + }); + + afterAll(() => { + baseEvent.range = []; + baseEvent.data.ordered = { date: false }; + }); + + test('creates a new range filter', async () => { + const rangeBegin = JAN_01_2014; + const rangeEnd = rangeBegin + DAY_IN_MS; + baseEvent.range = [rangeBegin, rangeEnd]; + const filter = await onBrushEvent(baseEvent); + + expect(filter).toBeDefined(); + + if (filter) { + expect(filter.range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString()); + expect(filter.range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString()); + expect(filter.range.anotherTimeField).toHaveProperty( + 'format', + 'strict_date_optional_time' + ); + } + }); + }); + }); + + describe('handles an event when the x-axis field is a number', () => { + beforeAll(() => { + aggConfigs[0].params.field = { + name: 'numberField', + type: 'number', + }; + }); + + afterAll(() => { + baseEvent.range = []; + }); + + test('by ignoring the event when range does not span at least 2 values', async () => { + baseEvent.range = [1]; + const filter = await onBrushEvent(baseEvent); + expect(filter).toBeUndefined(); + }); + + test('by creating a new filter', async () => { + baseEvent.range = [1, 2, 3, 4]; + const filter = await onBrushEvent(baseEvent); + + expect(filter).toBeDefined(); + + if (filter) { + expect(filter.range.numberField.gte).toBe(1); + expect(filter.range.numberField.lt).toBe(4); + expect(filter.range.numberField).not.toHaveProperty('format'); + } + }); + }); +}); diff --git a/src/legacy/core_plugins/data/public/actions/filters/brush_event.ts b/src/legacy/core_plugins/data/public/actions/filters/brush_event.ts new file mode 100644 index 0000000000000..00990d21ccf37 --- /dev/null +++ b/src/legacy/core_plugins/data/public/actions/filters/brush_event.ts @@ -0,0 +1,80 @@ +/* + * 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 { get, last } from 'lodash'; +import moment from 'moment'; +import { esFilters, IFieldType, RangeFilterParams } from '../../../../../../plugins/data/public'; +import { deserializeAggConfig } from '../../search/expressions/utils'; +// should be removed after moving into new platform plugins data folder +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getIndexPatterns } from '../../../../../../plugins/data/public/services'; + +export interface BrushEvent { + data: { + ordered: { + date: boolean; + }; + series: Array>; + }; + range: number[]; +} + +export async function onBrushEvent(event: BrushEvent) { + const isDate = get(event.data, 'ordered.date'); + const xRaw: Record = get(event.data, 'series[0].values[0].xRaw'); + + if (!xRaw) { + return; + } + + const column: Record = xRaw.table.columns[xRaw.column]; + + if (!column || !column.meta) { + return; + } + + const indexPattern = await getIndexPatterns().get(column.meta.indexPatternId); + const aggConfig = deserializeAggConfig({ + ...column.meta, + indexPattern, + }); + const field: IFieldType = aggConfig.params.field; + + if (!field || event.range.length <= 1) { + return; + } + + const min = event.range[0]; + const max = last(event.range); + + if (min === max) { + return; + } + + const range: RangeFilterParams = { + gte: isDate ? moment(min).toISOString() : min, + lt: isDate ? moment(max).toISOString() : max, + }; + + if (isDate) { + range.format = 'strict_date_optional_time'; + } + + return esFilters.buildRangeFilter(field, range, indexPattern); +} diff --git a/src/legacy/core_plugins/data/public/actions/select_range_action.ts b/src/legacy/core_plugins/data/public/actions/select_range_action.ts index 8d0b74be50535..7f1c5d78ab800 100644 --- a/src/legacy/core_plugins/data/public/actions/select_range_action.ts +++ b/src/legacy/core_plugins/data/public/actions/select_range_action.ts @@ -23,16 +23,8 @@ import { createAction, IncompatibleActionError, } from '../../../../../plugins/ui_actions/public'; -// @ts-ignore import { onBrushEvent } from './filters/brush_event'; -import { - Filter, - FilterManager, - TimefilterContract, - esFilters, -} from '../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getIndexPatterns } from '../../../../../plugins/data/public/services'; +import { FilterManager, TimefilterContract, esFilters } from '../../../../../plugins/data/public'; export const SELECT_RANGE_ACTION = 'SELECT_RANGE_ACTION'; @@ -43,8 +35,7 @@ interface ActionContext { async function isCompatible(context: ActionContext) { try { - const filters: Filter[] = (await onBrushEvent(context.data, getIndexPatterns)) || []; - return filters.length > 0; + return Boolean(await onBrushEvent(context.data)); } catch { return false; } @@ -68,9 +59,13 @@ export function selectRangeAction( throw new IncompatibleActionError(); } - const filters: Filter[] = (await onBrushEvent(data, getIndexPatterns)) || []; + const filter = await onBrushEvent(data); + + if (!filter) { + return; + } - const selectedFilters: Filter[] = esFilters.mapAndFlattenFilters(filters); + const selectedFilters = esFilters.mapAndFlattenFilters([filter]); if (timeFieldName) { const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( From 2ea4bdfe0dc61e303fa555a12788a3868e7510db Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Wed, 26 Feb 2020 07:14:08 -0600 Subject: [PATCH 087/123] Server-side license check for APM service map (#58547) * Factor our the license checking logic and messaging to common * Add licensing plugin as a dependency of the APM plugin * Throw a forbidden error on the server if trying to access the service map routes --- .../app/ServiceMap/PlatinumLicensePrompt.tsx | 18 ++++++------------ .../public/components/app/ServiceMap/index.tsx | 13 +++++++------ x-pack/plugins/apm/common/service_map.ts | 18 ++++++++++++++++++ x-pack/plugins/apm/kibana.json | 2 +- x-pack/plugins/apm/server/plugin.ts | 2 ++ .../plugins/apm/server/routes/service_map.ts | 17 ++++++++++++++--- 6 files changed, 48 insertions(+), 22 deletions(-) diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/PlatinumLicensePrompt.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/PlatinumLicensePrompt.tsx index c5771995daa24..9213349a1492b 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/PlatinumLicensePrompt.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/PlatinumLicensePrompt.tsx @@ -4,15 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; import { - EuiEmptyPrompt, EuiButton, - EuiPanel, + EuiEmptyPrompt, EuiFlexGroup, - EuiFlexItem + EuiFlexItem, + EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { invalidLicenseMessage } from '../../../../../../../plugins/apm/common/service_map'; import { useKibanaUrl } from '../../../hooks/useKibanaUrl'; export function PlatinumLicensePrompt() { @@ -43,14 +44,7 @@ export function PlatinumLicensePrompt() { )} ]} - body={ -

- {i18n.translate('xpack.apm.serviceMap.licensePromptBody', { - defaultMessage: - "In order to access Service Maps, you must be subscribed to an Elastic Platinum license. With it, you'll have the ability to visualize your entire application stack along with your APM data." - })} -

- } + body={

{invalidLicenseMessage}

} title={

{i18n.translate('xpack.apm.serviceMap.licensePromptTitle', { diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx index 5fea4be9ca0da..b14ecaa803f6d 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx @@ -17,12 +17,14 @@ import React, { useState } from 'react'; import { toMountPoint } from '../../../../../../../../src/plugins/kibana_react/public'; +import { isValidPlatinumLicense } from '../../../../../../../plugins/apm/common/service_map'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { ServiceMapAPIResponse } from '../../../../../../../plugins/apm/server/lib/service_map/get_service_map'; import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; import { useCallApmApi } from '../../../hooks/useCallApmApi'; import { useDeepObjectIdentity } from '../../../hooks/useDeepObjectIdentity'; import { useLicense } from '../../../hooks/useLicense'; +import { useLoadingIndicator } from '../../../hooks/useLoadingIndicator'; import { useLocation } from '../../../hooks/useLocation'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { Controls } from './Controls'; @@ -31,7 +33,6 @@ import { getCytoscapeElements } from './get_cytoscape_elements'; import { PlatinumLicensePrompt } from './PlatinumLicensePrompt'; import { Popover } from './Popover'; import { useRefHeight } from './useRefHeight'; -import { useLoadingIndicator } from '../../../hooks/useLoadingIndicator'; interface ServiceMapProps { serviceName?: string; @@ -195,13 +196,13 @@ export function ServiceMap({ serviceName }: ServiceMapProps) { // eslint-disable-next-line react-hooks/exhaustive-deps }, [elements]); - const isValidPlatinumLicense = - license?.isActive && - (license?.type === 'platinum' || license?.type === 'trial'); - const [wrapperRef, height] = useRefHeight(); - return isValidPlatinumLicense ? ( + if (!license) { + return null; + } + + return isValidPlatinumLicense(license) ? (
{ plugins: { apm_oss: APMOSSPlugin extends Plugin ? TSetup : never; home: HomeServerPluginSetup; + licensing: LicensingPluginSetup; cloud?: CloudSetup; usageCollection?: UsageCollectionSetup; } diff --git a/x-pack/plugins/apm/server/routes/service_map.ts b/x-pack/plugins/apm/server/routes/service_map.ts index 584598805f8b3..bead0445d6ccc 100644 --- a/x-pack/plugins/apm/server/routes/service_map.ts +++ b/x-pack/plugins/apm/server/routes/service_map.ts @@ -4,13 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as t from 'io-ts'; import Boom from 'boom'; +import * as t from 'io-ts'; +import { + invalidLicenseMessage, + isValidPlatinumLicense +} from '../../common/service_map'; import { setupRequest } from '../lib/helpers/setup_request'; -import { createRoute } from './create_route'; -import { uiFiltersRt, rangeRt } from './default_api_types'; import { getServiceMap } from '../lib/service_map/get_service_map'; import { getServiceMapServiceNodeInfo } from '../lib/service_map/get_service_map_service_node_info'; +import { createRoute } from './create_route'; +import { rangeRt, uiFiltersRt } from './default_api_types'; export const serviceMapRoute = createRoute(() => ({ path: '/api/apm/service-map', @@ -26,6 +30,10 @@ export const serviceMapRoute = createRoute(() => ({ if (!context.config['xpack.apm.serviceMapEnabled']) { throw Boom.notFound(); } + if (!isValidPlatinumLicense(context.licensing.license)) { + throw Boom.forbidden(invalidLicenseMessage); + } + const setup = await setupRequest(context, request); const { query: { serviceName, environment, after } @@ -51,6 +59,9 @@ export const serviceMapServiceNodeRoute = createRoute(() => ({ if (!context.config['xpack.apm.serviceMapEnabled']) { throw Boom.notFound(); } + if (!isValidPlatinumLicense(context.licensing.license)) { + throw Boom.forbidden(invalidLicenseMessage); + } const setup = await setupRequest(context, request); const { From 3212754e62a73f75dd055d5c9e8eb1e43a5dec29 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 26 Feb 2020 07:50:11 -0700 Subject: [PATCH 088/123] [Maps] add Top term aggregation (#57875) * [Maps] add Top term aggregation * update pew-pew source to handle terms agg * make helper function for pulling values from bucket * update terms source * better join labels * categoricla meta * remove unused constant * remove unused changes * remove unused constant METRIC_SCHEMA_CONFIG * update jest expect * fix auto complete suggestions for top term * get category autocomplete working with style props from joins * pluck categorical style meta with real field name * mock MetricsEditor to fix jest test * review feedback * es_agg_utils.js to es_agg_utils.ts * typing updates * use composit agg to avoid search.buckets limit * i18n update and functional test fix * stop paging through results when request is aborted * remove unused file * do not use composite agg when no terms sub-aggregations * clean up * pass indexPattern to getValueAggsDsl * review feedback * more review feedback * ts-ignore for untyped imports in tests * more review feedback * add bucket.hasOwnProperty check Co-authored-by: Elastic Machine --- .../legacy/plugins/maps/common/constants.ts | 4 +- .../maps/public/actions/map_actions.js | 22 +- .../maps/public/components/metric_editor.js | 13 +- .../maps/public/components/metric_select.js | 20 +- .../maps/public/components/metrics_editor.js | 4 +- .../resources/metrics_expression.js | 8 +- .../resources/metrics_expression.test.js | 6 + .../connected_components/map/mb/view.js | 15 +- .../maps/public/elasticsearch_geo_utils.js | 18 ++ .../maps/public/layers/fields/es_agg_field.js | 33 ++- .../public/layers/fields/es_agg_field.test.js | 14 +- .../public/layers/sources/es_agg_source.js | 38 ++-- .../es_geo_grid_source/convert_to_geojson.js | 89 ++++---- .../convert_to_geojson.test.ts | 159 ++++++++++++++ .../es_geo_grid_source/es_geo_grid_source.js | 201 ++++++++++++++---- .../es_geo_grid_source/geo_tile_utils.js | 3 +- .../es_geo_grid_source/geo_tile_utils.test.js | 2 + .../es_pew_pew_source/convert_to_lines.js | 19 +- .../convert_to_lines.test.ts | 68 ++++++ .../es_pew_pew_source/es_pew_pew_source.js | 8 +- .../es_search_source/es_search_source.js | 26 +-- .../maps/public/layers/sources/es_source.js | 11 +- .../public/layers/sources/es_term_source.js | 91 +++----- .../layers/sources/es_term_source.test.js | 91 +------- .../properties/dynamic_size_property.js | 12 +- .../properties/dynamic_style_property.js | 27 ++- .../layers/styles/vector/vector_style.js | 10 +- .../tooltips/es_aggmetric_tooltip_property.js | 6 +- .../public/layers/util/es_agg_utils.test.ts | 37 ++++ .../maps/public/layers/util/es_agg_utils.ts | 51 +++++ .../public/layers/util/is_metric_countable.js | 4 +- .../maps/public/layers/vector_layer.js | 15 +- .../maps/public/selectors/map_selectors.js | 15 ++ .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 35 files changed, 726 insertions(+), 416 deletions(-) create mode 100644 x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/convert_to_geojson.test.ts create mode 100644 x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/convert_to_lines.test.ts create mode 100644 x-pack/legacy/plugins/maps/public/layers/util/es_agg_utils.test.ts create mode 100644 x-pack/legacy/plugins/maps/public/layers/util/es_agg_utils.ts diff --git a/x-pack/legacy/plugins/maps/common/constants.ts b/x-pack/legacy/plugins/maps/common/constants.ts index ab9a696fa3a17..542abfb004d0d 100644 --- a/x-pack/legacy/plugins/maps/common/constants.ts +++ b/x-pack/legacy/plugins/maps/common/constants.ts @@ -117,16 +117,16 @@ export const DRAW_TYPE = { POLYGON: 'POLYGON', }; -export const METRIC_TYPE = { +export const AGG_TYPE = { AVG: 'avg', COUNT: 'count', MAX: 'max', MIN: 'min', SUM: 'sum', + TERMS: 'terms', UNIQUE_COUNT: 'cardinality', }; -export const COUNT_AGG_TYPE = METRIC_TYPE.COUNT; export const COUNT_PROP_LABEL = i18n.translate('xpack.maps.aggs.defaultCountLabel', { defaultMessage: 'count', }); diff --git a/x-pack/legacy/plugins/maps/public/actions/map_actions.js b/x-pack/legacy/plugins/maps/public/actions/map_actions.js index 2c6c60db9a012..cfca044ea759a 100644 --- a/x-pack/legacy/plugins/maps/public/actions/map_actions.js +++ b/x-pack/legacy/plugins/maps/public/actions/map_actions.js @@ -18,6 +18,7 @@ import { getTransientLayerId, getOpenTooltips, getQuery, + getDataRequestDescriptor, } from '../selectors/map_selectors'; import { FLYOUT_STATE } from '../reducers/ui'; import { @@ -76,7 +77,7 @@ export const HIDE_LAYER_CONTROL = 'HIDE_LAYER_CONTROL'; export const HIDE_VIEW_CONTROL = 'HIDE_VIEW_CONTROL'; export const SET_WAITING_FOR_READY_HIDDEN_LAYERS = 'SET_WAITING_FOR_READY_HIDDEN_LAYERS'; -function getLayerLoadingCallbacks(dispatch, layerId) { +function getLayerLoadingCallbacks(dispatch, getState, layerId) { return { startLoading: (dataId, requestToken, meta) => dispatch(startDataLoad(layerId, dataId, requestToken, meta)), @@ -87,6 +88,13 @@ function getLayerLoadingCallbacks(dispatch, layerId) { updateSourceData: newData => { dispatch(updateSourceDataRequest(layerId, newData)); }, + isRequestStillActive: (dataId, requestToken) => { + const dataRequest = getDataRequestDescriptor(getState(), layerId, dataId); + if (!dataRequest) { + return false; + } + return dataRequest.dataRequestToken === requestToken; + }, registerCancelCallback: (requestToken, callback) => dispatch(registerCancelCallback(requestToken, callback)), }; @@ -98,11 +106,11 @@ function getLayerById(layerId, state) { }); } -async function syncDataForAllLayers(getState, dispatch, dataFilters) { +async function syncDataForAllLayers(dispatch, getState, dataFilters) { const state = getState(); const layerList = getLayerList(state); const syncs = layerList.map(layer => { - const loadingFunctions = getLayerLoadingCallbacks(dispatch, layer.getId()); + const loadingFunctions = getLayerLoadingCallbacks(dispatch, getState, layer.getId()); return layer.syncData({ ...loadingFunctions, dataFilters }); }); await Promise.all(syncs); @@ -412,7 +420,7 @@ export function mapExtentChanged(newMapConstants) { }, }); const newDataFilters = { ...dataFilters, ...newMapConstants }; - await syncDataForAllLayers(getState, dispatch, newDataFilters); + await syncDataForAllLayers(dispatch, getState, newDataFilters); }; } @@ -653,7 +661,7 @@ export function syncDataForLayer(layerId) { const targetLayer = getLayerById(layerId, getState()); if (targetLayer) { const dataFilters = getDataFilters(getState()); - const loadingFunctions = getLayerLoadingCallbacks(dispatch, layerId); + const loadingFunctions = getLayerLoadingCallbacks(dispatch, getState, layerId); await targetLayer.syncData({ ...loadingFunctions, dataFilters, @@ -773,7 +781,7 @@ export function setQuery({ query, timeFilters, filters = [], refresh = false }) }); const dataFilters = getDataFilters(getState()); - await syncDataForAllLayers(getState, dispatch, dataFilters); + await syncDataForAllLayers(dispatch, getState, dataFilters); }; } @@ -792,7 +800,7 @@ export function triggerRefreshTimer() { }); const dataFilters = getDataFilters(getState()); - await syncDataForAllLayers(getState, dispatch, dataFilters); + await syncDataForAllLayers(dispatch, getState, dataFilters); }; } diff --git a/x-pack/legacy/plugins/maps/public/components/metric_editor.js b/x-pack/legacy/plugins/maps/public/components/metric_editor.js index e60c2ac0dd7ab..530f402592b2b 100644 --- a/x-pack/legacy/plugins/maps/public/components/metric_editor.js +++ b/x-pack/legacy/plugins/maps/public/components/metric_editor.js @@ -12,17 +12,16 @@ import { EuiFieldText, EuiFormRow } from '@elastic/eui'; import { MetricSelect, METRIC_AGGREGATION_VALUES } from './metric_select'; import { SingleFieldSelect } from './single_field_select'; -import { METRIC_TYPE } from '../../common/constants'; +import { AGG_TYPE } from '../../common/constants'; +import { getTermsFields } from '../index_pattern_util'; function filterFieldsForAgg(fields, aggType) { if (!fields) { return []; } - if (aggType === METRIC_TYPE.UNIQUE_COUNT) { - return fields.filter(field => { - return field.aggregatable; - }); + if (aggType === AGG_TYPE.UNIQUE_COUNT || aggType === AGG_TYPE.TERMS) { + return getTermsFields(fields); } return fields.filter(field => { @@ -38,7 +37,7 @@ export function MetricEditor({ fields, metricsFilter, metric, onChange, removeBu }; // unset field when new agg type does not support currently selected field. - if (metric.field && metricAggregationType !== METRIC_TYPE.COUNT) { + if (metric.field && metricAggregationType !== AGG_TYPE.COUNT) { const fieldsForNewAggType = filterFieldsForAgg(fields, metricAggregationType); const found = fieldsForNewAggType.find(field => { return field.name === metric.field; @@ -64,7 +63,7 @@ export function MetricEditor({ fields, metricsFilter, metric, onChange, removeBu }; let fieldSelect; - if (metric.type && metric.type !== METRIC_TYPE.COUNT) { + if (metric.type && metric.type !== AGG_TYPE.COUNT) { fieldSelect = ( { - if (type === METRIC_TYPE.COUNT) { + if (type === AGG_TYPE.COUNT) { return true; } @@ -70,7 +70,7 @@ export class MetricsExpression extends Component { }) .map(({ type, field }) => { // do not use metric label so field and aggregation are not obscured. - if (type === METRIC_TYPE.COUNT) { + if (type === AGG_TYPE.COUNT) { return 'count'; } @@ -130,5 +130,5 @@ MetricsExpression.propTypes = { }; MetricsExpression.defaultProps = { - metrics: [{ type: METRIC_TYPE.COUNT }], + metrics: [{ type: AGG_TYPE.COUNT }], }; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js index e0e1556ecde06..e4e3776c8e92c 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js @@ -4,6 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ +jest.mock('../../../../components/metrics_editor', () => ({ + MetricsEditor: () => { + return
mockMetricsEditor
; + }, +})); + import React from 'react'; import { shallow } from 'enzyme'; import { MetricsExpression } from './metrics_expression'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/view.js b/x-pack/legacy/plugins/maps/public/connected_components/map/mb/view.js index 1e44c7225a564..fdc8ad2176d08 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/view.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/map/mb/view.js @@ -23,6 +23,7 @@ import sprites1 from '@elastic/maki/dist/sprite@1.png'; import sprites2 from '@elastic/maki/dist/sprite@2.png'; import { DrawControl } from './draw_control'; import { TooltipControl } from './tooltip_control'; +import { clampToLatBounds, clampToLonBounds } from '../../../elasticsearch_geo_utils'; mapboxgl.workerUrl = mbWorkerUrl; mapboxgl.setRTLTextPlugin(mbRtlPlugin); @@ -234,12 +235,12 @@ export class MBMapContainer extends React.Component { //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( - clamp(goto.bounds.min_lon, -180, 180), - clamp(goto.bounds.min_lat, -89, 89) + clampToLonBounds(goto.bounds.min_lon), + clampToLatBounds(goto.bounds.min_lat) ), new mapboxgl.LngLat( - clamp(goto.bounds.max_lon, -180, 180), - clamp(goto.bounds.max_lat, -89, 89) + clampToLonBounds(goto.bounds.max_lon), + clampToLatBounds(goto.bounds.max_lat) ) ); //maxZoom ensure we're not zooming in too far on single points or small shapes @@ -306,9 +307,3 @@ export class MBMapContainer extends React.Component { ); } } - -function clamp(val, min, max) { - if (val > max) val = max; - else if (val < min) val = min; - return val; -} diff --git a/x-pack/legacy/plugins/maps/public/elasticsearch_geo_utils.js b/x-pack/legacy/plugins/maps/public/elasticsearch_geo_utils.js index ec0ae4161b3f2..9b33d3036785c 100644 --- a/x-pack/legacy/plugins/maps/public/elasticsearch_geo_utils.js +++ b/x-pack/legacy/plugins/maps/public/elasticsearch_geo_utils.js @@ -433,3 +433,21 @@ export function convertMapExtentToPolygon({ maxLat, maxLon, minLat, minLon }) { return formatEnvelopeAsPolygon({ maxLat, maxLon, minLat, minLon }); } + +export function clampToLatBounds(lat) { + return clamp(lat, -89, 89); +} + +export function clampToLonBounds(lon) { + return clamp(lon, -180, 180); +} + +export function clamp(val, min, max) { + if (val > max) { + return max; + } else if (val < min) { + return min; + } else { + return val; + } +} diff --git a/x-pack/legacy/plugins/maps/public/layers/fields/es_agg_field.js b/x-pack/legacy/plugins/maps/public/layers/fields/es_agg_field.js index 65109cb99809f..28c199b64d3ef 100644 --- a/x-pack/legacy/plugins/maps/public/layers/fields/es_agg_field.js +++ b/x-pack/legacy/plugins/maps/public/layers/fields/es_agg_field.js @@ -5,9 +5,10 @@ */ import { AbstractField } from './field'; -import { COUNT_AGG_TYPE } from '../../../common/constants'; +import { AGG_TYPE } from '../../../common/constants'; import { isMetricCountable } from '../util/is_metric_countable'; import { ESAggMetricTooltipProperty } from '../tooltips/es_aggmetric_tooltip_property'; +import { getField, addFieldToDSL } from '../util/es_agg_utils'; export class ESAggMetricField extends AbstractField { static type = 'ES_AGG'; @@ -34,12 +35,11 @@ export class ESAggMetricField extends AbstractField { } isValid() { - return this.getAggType() === COUNT_AGG_TYPE ? true : !!this._esDocField; + return this.getAggType() === AGG_TYPE.COUNT ? true : !!this._esDocField; } async getDataType() { - // aggregations only provide numerical data - return 'number'; + return this.getAggType() === AGG_TYPE.TERMS ? 'string' : 'number'; } getESDocFieldName() { @@ -47,9 +47,9 @@ export class ESAggMetricField extends AbstractField { } getRequestDescription() { - return this.getAggType() !== COUNT_AGG_TYPE + return this.getAggType() !== AGG_TYPE.COUNT ? `${this.getAggType()} ${this.getESDocFieldName()}` - : COUNT_AGG_TYPE; + : AGG_TYPE.COUNT; } async createTooltipProperty(value) { @@ -63,18 +63,13 @@ export class ESAggMetricField extends AbstractField { ); } - makeMetricAggConfig() { - const metricAggConfig = { - id: this.getName(), - enabled: true, - type: this.getAggType(), - schema: 'metric', - params: {}, + getValueAggDsl(indexPattern) { + const field = getField(indexPattern, this.getESDocFieldName()); + const aggType = this.getAggType(); + const aggBody = aggType === AGG_TYPE.TERMS ? { size: 1, shard_size: 1 } : {}; + return { + [aggType]: addFieldToDSL(aggBody, field), }; - if (this.getAggType() !== COUNT_AGG_TYPE) { - metricAggConfig.params = { field: this.getESDocFieldName() }; - } - return metricAggConfig; } supportsFieldMeta() { @@ -85,4 +80,8 @@ export class ESAggMetricField extends AbstractField { async getOrdinalFieldMetaRequest(config) { return this._esDocField.getOrdinalFieldMetaRequest(config); } + + async getCategoricalFieldMetaRequest() { + return this._esDocField.getCategoricalFieldMetaRequest(); + } } diff --git a/x-pack/legacy/plugins/maps/public/layers/fields/es_agg_field.test.js b/x-pack/legacy/plugins/maps/public/layers/fields/es_agg_field.test.js index 2f18987513d92..aeeffd63607ee 100644 --- a/x-pack/legacy/plugins/maps/public/layers/fields/es_agg_field.test.js +++ b/x-pack/legacy/plugins/maps/public/layers/fields/es_agg_field.test.js @@ -5,24 +5,24 @@ */ import { ESAggMetricField } from './es_agg_field'; -import { METRIC_TYPE } from '../../../common/constants'; +import { AGG_TYPE } from '../../../common/constants'; describe('supportsFieldMeta', () => { test('Non-counting aggregations should support field meta', () => { - const avgMetric = new ESAggMetricField({ aggType: METRIC_TYPE.AVG }); + const avgMetric = new ESAggMetricField({ aggType: AGG_TYPE.AVG }); expect(avgMetric.supportsFieldMeta()).toBe(true); - const maxMetric = new ESAggMetricField({ aggType: METRIC_TYPE.MAX }); + const maxMetric = new ESAggMetricField({ aggType: AGG_TYPE.MAX }); expect(maxMetric.supportsFieldMeta()).toBe(true); - const minMetric = new ESAggMetricField({ aggType: METRIC_TYPE.MIN }); + const minMetric = new ESAggMetricField({ aggType: AGG_TYPE.MIN }); expect(minMetric.supportsFieldMeta()).toBe(true); }); test('Counting aggregations should not support field meta', () => { - const countMetric = new ESAggMetricField({ aggType: METRIC_TYPE.COUNT }); + const countMetric = new ESAggMetricField({ aggType: AGG_TYPE.COUNT }); expect(countMetric.supportsFieldMeta()).toBe(false); - const sumMetric = new ESAggMetricField({ aggType: METRIC_TYPE.SUM }); + const sumMetric = new ESAggMetricField({ aggType: AGG_TYPE.SUM }); expect(sumMetric.supportsFieldMeta()).toBe(false); - const uniqueCountMetric = new ESAggMetricField({ aggType: METRIC_TYPE.UNIQUE_COUNT }); + const uniqueCountMetric = new ESAggMetricField({ aggType: AGG_TYPE.UNIQUE_COUNT }); expect(uniqueCountMetric.supportsFieldMeta()).toBe(false); }); }); diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_agg_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_agg_source.js index 967a3c41aec26..bee35216f59da 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_agg_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_agg_source.js @@ -8,8 +8,7 @@ import { AbstractESSource } from './es_source'; import { ESAggMetricField } from '../fields/es_agg_field'; import { ESDocField } from '../fields/es_doc_field'; import { - METRIC_TYPE, - COUNT_AGG_TYPE, + AGG_TYPE, COUNT_PROP_LABEL, COUNT_PROP_NAME, FIELD_ORIGIN, @@ -18,23 +17,6 @@ import { export const AGG_DELIMITER = '_of_'; export class AbstractESAggSource extends AbstractESSource { - static METRIC_SCHEMA_CONFIG = { - group: 'metrics', - name: 'metric', - title: 'Value', - min: 1, - max: Infinity, - aggFilter: [ - METRIC_TYPE.AVG, - METRIC_TYPE.COUNT, - METRIC_TYPE.MAX, - METRIC_TYPE.MIN, - METRIC_TYPE.SUM, - METRIC_TYPE.UNIQUE_COUNT, - ], - defaults: [{ schema: 'metric', type: METRIC_TYPE.COUNT }], - }; - constructor(descriptor, inspectorAdapters) { super(descriptor, inspectorAdapters); this._metricFields = this._descriptor.metrics @@ -81,7 +63,7 @@ export class AbstractESAggSource extends AbstractESSource { if (metrics.length === 0) { metrics.push( new ESAggMetricField({ - aggType: COUNT_AGG_TYPE, + aggType: AGG_TYPE.COUNT, source: this, origin: this.getOriginForField(), }) @@ -91,15 +73,23 @@ export class AbstractESAggSource extends AbstractESSource { } formatMetricKey(aggType, fieldName) { - return aggType !== COUNT_AGG_TYPE ? `${aggType}${AGG_DELIMITER}${fieldName}` : COUNT_PROP_NAME; + return aggType !== AGG_TYPE.COUNT ? `${aggType}${AGG_DELIMITER}${fieldName}` : COUNT_PROP_NAME; } formatMetricLabel(aggType, fieldName) { - return aggType !== COUNT_AGG_TYPE ? `${aggType} of ${fieldName}` : COUNT_PROP_LABEL; + return aggType !== AGG_TYPE.COUNT ? `${aggType} of ${fieldName}` : COUNT_PROP_LABEL; } - createMetricAggConfigs() { - return this.getMetricFields().map(esAggMetric => esAggMetric.makeMetricAggConfig()); + getValueAggsDsl(indexPattern) { + const valueAggsDsl = {}; + this.getMetricFields() + .filter(esAggMetric => { + return esAggMetric.getAggType() !== AGG_TYPE.COUNT; + }) + .forEach(esAggMetric => { + valueAggsDsl[esAggMetric.getName()] = esAggMetric.getValueAggDsl(indexPattern); + }); + return valueAggsDsl; } async getNumberFields() { diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/convert_to_geojson.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/convert_to_geojson.js index 4e15d1c927c36..bb9bf1b508f94 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/convert_to_geojson.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/convert_to_geojson.js @@ -4,68 +4,63 @@ * you may not use this file except in compliance with the Elastic License. */ +import _ from 'lodash'; import { RENDER_AS } from './render_as'; import { getTileBoundingBox } from './geo_tile_utils'; -import { EMPTY_FEATURE_COLLECTION } from '../../../../common/constants'; +import { extractPropertiesFromBucket } from '../../util/es_agg_utils'; +import { clamp } from '../../../elasticsearch_geo_utils'; -export function convertToGeoJson({ table, renderAs }) { - if (!table || !table.rows) { - return EMPTY_FEATURE_COLLECTION; - } +const GRID_BUCKET_KEYS_TO_IGNORE = ['key', 'gridCentroid']; - const geoGridColumn = table.columns.find( - column => column.aggConfig.type.dslName === 'geotile_grid' +export function convertCompositeRespToGeoJson(esResponse, renderAs) { + return convertToGeoJson( + esResponse, + renderAs, + esResponse => { + return _.get(esResponse, 'aggregations.compositeSplit.buckets', []); + }, + gridBucket => { + return gridBucket.key.gridSplit; + } ); - if (!geoGridColumn) { - return EMPTY_FEATURE_COLLECTION; - } +} - const metricColumns = table.columns.filter(column => { - return ( - column.aggConfig.type.type === 'metrics' && column.aggConfig.type.dslName !== 'geo_centroid' - ); - }); - const geocentroidColumn = table.columns.find( - column => column.aggConfig.type.dslName === 'geo_centroid' +export function convertRegularRespToGeoJson(esResponse, renderAs) { + return convertToGeoJson( + esResponse, + renderAs, + esResponse => { + return _.get(esResponse, 'aggregations.gridSplit.buckets', []); + }, + gridBucket => { + return gridBucket.key; + } ); - if (!geocentroidColumn) { - return EMPTY_FEATURE_COLLECTION; - } +} +function convertToGeoJson(esResponse, renderAs, pluckGridBuckets, pluckGridKey) { const features = []; - table.rows.forEach(row => { - const gridKey = row[geoGridColumn.id]; - if (!gridKey) { - return; - } - - const properties = {}; - metricColumns.forEach(metricColumn => { - properties[metricColumn.aggConfig.id] = row[metricColumn.id]; - }); + const gridBuckets = pluckGridBuckets(esResponse); + for (let i = 0; i < gridBuckets.length; i++) { + const gridBucket = gridBuckets[i]; + const gridKey = pluckGridKey(gridBucket); features.push({ type: 'Feature', geometry: rowToGeometry({ - row, gridKey, - geocentroidColumn, + gridCentroid: gridBucket.gridCentroid, renderAs, }), id: gridKey, - properties, + properties: extractPropertiesFromBucket(gridBucket, GRID_BUCKET_KEYS_TO_IGNORE), }); - }); + } - return { - featureCollection: { - type: 'FeatureCollection', - features: features, - }, - }; + return features; } -function rowToGeometry({ row, gridKey, geocentroidColumn, renderAs }) { +function rowToGeometry({ gridKey, gridCentroid, renderAs }) { const { top, bottom, right, left } = getTileBoundingBox(gridKey); if (renderAs === RENDER_AS.GRID) { @@ -83,10 +78,10 @@ function rowToGeometry({ row, gridKey, geocentroidColumn, renderAs }) { }; } - // see https://github.com/elastic/elasticsearch/issues/24694 for why clampGrid is used + // see https://github.com/elastic/elasticsearch/issues/24694 for why clamp is used const pointCoordinates = [ - clampGrid(row[geocentroidColumn.id].lon, left, right), - clampGrid(row[geocentroidColumn.id].lat, bottom, top), + clamp(gridCentroid.location.lon, left, right), + clamp(gridCentroid.location.lat, bottom, top), ]; return { @@ -94,9 +89,3 @@ function rowToGeometry({ row, gridKey, geocentroidColumn, renderAs }) { coordinates: pointCoordinates, }; } - -function clampGrid(val, min, max) { - if (val > max) val = max; - else if (val < min) val = min; - return val; -} diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/convert_to_geojson.test.ts b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/convert_to_geojson.test.ts new file mode 100644 index 0000000000000..ba79464a01a9b --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/convert_to_geojson.test.ts @@ -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. + */ + +jest.mock('../../../kibana_services', () => {}); + +// @ts-ignore +import { convertCompositeRespToGeoJson, convertRegularRespToGeoJson } from './convert_to_geojson'; +// @ts-ignore +import { RENDER_AS } from './render_as'; + +describe('convertCompositeRespToGeoJson', () => { + const esResponse = { + aggregations: { + compositeSplit: { + after_key: { + gridSplit: '10/327/460', + }, + buckets: [ + { + key: { gridSplit: '4/4/6' }, + doc_count: 65, + avg_of_bytes: { value: 5359.2307692307695 }, + 'terms_of_machine.os.keyword': { + buckets: [ + { + key: 'win xp', + doc_count: 16, + }, + ], + }, + gridCentroid: { + location: { lat: 36.62813963153614, lon: -81.94552666092149 }, + count: 65, + }, + }, + ], + }, + }, + }; + + it('Should convert elasticsearch aggregation response into feature collection of points', () => { + const features = convertCompositeRespToGeoJson(esResponse, RENDER_AS.POINT); + expect(features.length).toBe(1); + expect(features[0]).toEqual({ + geometry: { + coordinates: [-81.94552666092149, 36.62813963153614], + type: 'Point', + }, + id: '4/4/6', + properties: { + avg_of_bytes: 5359.2307692307695, + doc_count: 65, + 'terms_of_machine.os.keyword': 'win xp', + }, + type: 'Feature', + }); + }); + + it('Should convert elasticsearch aggregation response into feature collection of Polygons', () => { + const features = convertCompositeRespToGeoJson(esResponse, RENDER_AS.GRID); + expect(features.length).toBe(1); + expect(features[0]).toEqual({ + geometry: { + coordinates: [ + [ + [-67.5, 40.9799], + [-90, 40.9799], + [-90, 21.94305], + [-67.5, 21.94305], + [-67.5, 40.9799], + ], + ], + type: 'Polygon', + }, + id: '4/4/6', + properties: { + avg_of_bytes: 5359.2307692307695, + doc_count: 65, + 'terms_of_machine.os.keyword': 'win xp', + }, + type: 'Feature', + }); + }); +}); + +describe('convertRegularRespToGeoJson', () => { + const esResponse = { + aggregations: { + gridSplit: { + buckets: [ + { + key: '4/4/6', + doc_count: 65, + avg_of_bytes: { value: 5359.2307692307695 }, + 'terms_of_machine.os.keyword': { + buckets: [ + { + key: 'win xp', + doc_count: 16, + }, + ], + }, + gridCentroid: { + location: { lat: 36.62813963153614, lon: -81.94552666092149 }, + count: 65, + }, + }, + ], + }, + }, + }; + + it('Should convert elasticsearch aggregation response into feature collection of points', () => { + const features = convertRegularRespToGeoJson(esResponse, RENDER_AS.POINT); + expect(features.length).toBe(1); + expect(features[0]).toEqual({ + geometry: { + coordinates: [-81.94552666092149, 36.62813963153614], + type: 'Point', + }, + id: '4/4/6', + properties: { + avg_of_bytes: 5359.2307692307695, + doc_count: 65, + 'terms_of_machine.os.keyword': 'win xp', + }, + type: 'Feature', + }); + }); + + it('Should convert elasticsearch aggregation response into feature collection of Polygons', () => { + const features = convertRegularRespToGeoJson(esResponse, RENDER_AS.GRID); + expect(features.length).toBe(1); + expect(features[0]).toEqual({ + geometry: { + coordinates: [ + [ + [-67.5, 40.9799], + [-90, 40.9799], + [-90, 21.94305], + [-67.5, 21.94305], + [-67.5, 40.9799], + ], + ], + type: 'Polygon', + }, + id: '4/4/6', + properties: { + avg_of_bytes: 5359.2307692307695, + doc_count: 65, + 'terms_of_machine.os.keyword': 'win xp', + }, + type: 'Feature', + }); + }); +}); diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js index 0912e5a9f1283..a0ddf584bcebc 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js @@ -10,9 +10,7 @@ import uuid from 'uuid/v4'; import { VECTOR_SHAPE_TYPES } from '../vector_feature_types'; import { HeatmapLayer } from '../../heatmap_layer'; import { VectorLayer } from '../../vector_layer'; -import { AggConfigs, Schemas } from 'ui/agg_types'; -import { tabifyAggResponse } from '../../../../../../../../src/legacy/core_plugins/data/public'; -import { convertToGeoJson } from './convert_to_geojson'; +import { convertCompositeRespToGeoJson, convertRegularRespToGeoJson } from './convert_to_geojson'; import { VectorStyle } from '../../styles/vector/vector_style'; import { getDefaultDynamicProperties, @@ -24,6 +22,8 @@ import { CreateSourceEditor } from './create_source_editor'; import { UpdateSourceEditor } from './update_source_editor'; import { GRID_RESOLUTION } from '../../grid_resolution'; import { + AGG_TYPE, + DEFAULT_MAX_BUCKETS_LIMIT, SOURCE_DATA_ID_ORIGIN, ES_GEO_GRID, COUNT_PROP_NAME, @@ -34,21 +34,10 @@ import { getDataSourceLabel } from '../../../../common/i18n_getters'; import { AbstractESAggSource } from '../es_agg_source'; import { DynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property'; import { StaticStyleProperty } from '../../styles/vector/properties/static_style_property'; +import { DataRequestAbortError } from '../../util/data_request'; const MAX_GEOTILE_LEVEL = 29; -const aggSchemas = new Schemas([ - AbstractESAggSource.METRIC_SCHEMA_CONFIG, - { - group: 'buckets', - name: 'segment', - title: 'Geo Grid', - aggFilter: 'geotile_grid', - min: 1, - max: 1, - }, -]); - export class ESGeoGridSource extends AbstractESAggSource { static type = ES_GEO_GRID; static title = i18n.translate('xpack.maps.source.esGridTitle', { @@ -175,15 +164,120 @@ export class ESGeoGridSource extends AbstractESAggSource { ); } - async getGeoJsonWithMeta(layerName, searchFilters, registerCancelCallback) { - const indexPattern = await this.getIndexPattern(); - const searchSource = await this._makeSearchSource(searchFilters, 0); - const aggConfigs = new AggConfigs( - indexPattern, - this._makeAggConfigs(searchFilters.geogridPrecision), - aggSchemas.all - ); - searchSource.setField('aggs', aggConfigs.toDsl()); + async _compositeAggRequest({ + searchSource, + indexPattern, + precision, + layerName, + registerCancelCallback, + bucketsPerGrid, + isRequestStillActive, + }) { + const gridsPerRequest = Math.floor(DEFAULT_MAX_BUCKETS_LIMIT / bucketsPerGrid); + const aggs = { + compositeSplit: { + composite: { + size: gridsPerRequest, + sources: [ + { + gridSplit: { + geotile_grid: { + field: this._descriptor.geoField, + precision, + }, + }, + }, + ], + }, + aggs: { + gridCentroid: { + geo_centroid: { + field: this._descriptor.geoField, + }, + }, + ...this.getValueAggsDsl(indexPattern), + }, + }, + }; + + const features = []; + let requestCount = 0; + let afterKey = null; + while (true) { + if (!isRequestStillActive()) { + // Stop paging through results if request is obsolete + throw new DataRequestAbortError(); + } + + requestCount++; + + // circuit breaker to ensure reasonable number of requests + if (requestCount > 5) { + throw new Error( + i18n.translate('xpack.maps.source.esGrid.compositePaginationErrorMessage', { + defaultMessage: `{layerName} is causing too many requests. Reduce "Grid resolution" and/or reduce the number of top term "Metrics".`, + values: { layerName }, + }) + ); + } + + if (afterKey) { + aggs.compositeSplit.composite.after = afterKey; + } + searchSource.setField('aggs', aggs); + const requestId = afterKey ? `${this.getId()} afterKey ${afterKey.geoSplit}` : this.getId(); + const esResponse = await this._runEsQuery({ + requestId, + requestName: `${layerName} (${requestCount})`, + searchSource, + registerCancelCallback, + requestDescription: i18n.translate( + 'xpack.maps.source.esGrid.compositeInspectorDescription', + { + defaultMessage: 'Elasticsearch geo grid aggregation request: {requestId}', + values: { requestId }, + } + ), + }); + + features.push(...convertCompositeRespToGeoJson(esResponse, this._descriptor.requestType)); + + afterKey = esResponse.aggregations.compositeSplit.after_key; + if (esResponse.aggregations.compositeSplit.buckets.length < gridsPerRequest) { + // Finished because request did not get full resultset back + break; + } + } + + return features; + } + + // Do not use composite aggregation when there are no terms sub-aggregations + // see https://github.com/elastic/kibana/pull/57875#issuecomment-590515482 for explanation on using separate code paths + async _nonCompositeAggRequest({ + searchSource, + indexPattern, + precision, + layerName, + registerCancelCallback, + }) { + searchSource.setField('aggs', { + gridSplit: { + geotile_grid: { + field: this._descriptor.geoField, + precision, + }, + aggs: { + gridCentroid: { + geo_centroid: { + field: this._descriptor.geoField, + }, + }, + ...this.getValueAggsDsl(indexPattern), + }, + }, + }); + const esResponse = await this._runEsQuery({ requestId: this.getId(), requestName: layerName, @@ -194,14 +288,45 @@ export class ESGeoGridSource extends AbstractESAggSource { }), }); - const tabifiedResp = tabifyAggResponse(aggConfigs, esResponse); - const { featureCollection } = convertToGeoJson({ - table: tabifiedResp, - renderAs: this._descriptor.requestType, + return convertRegularRespToGeoJson(esResponse, this._descriptor.requestType); + } + + async getGeoJsonWithMeta(layerName, searchFilters, registerCancelCallback, isRequestStillActive) { + const indexPattern = await this.getIndexPattern(); + const searchSource = await this._makeSearchSource(searchFilters, 0); + + let bucketsPerGrid = 1; + this.getMetricFields().forEach(metricField => { + if (metricField.getAggType() === AGG_TYPE.TERMS) { + // each terms aggregation increases the overall number of buckets per grid + bucketsPerGrid++; + } }); + const features = + bucketsPerGrid === 1 + ? await this._nonCompositeAggRequest({ + searchSource, + indexPattern, + precision: searchFilters.geogridPrecision, + layerName, + registerCancelCallback, + }) + : await this._compositeAggRequest({ + searchSource, + indexPattern, + precision: searchFilters.geogridPrecision, + layerName, + registerCancelCallback, + bucketsPerGrid, + isRequestStillActive, + }); + return { - data: featureCollection, + data: { + type: 'FeatureCollection', + features: features, + }, meta: { areResultsTrimmed: false, }, @@ -212,24 +337,6 @@ export class ESGeoGridSource extends AbstractESAggSource { return true; } - _makeAggConfigs(precision) { - const metricAggConfigs = this.createMetricAggConfigs(); - return [ - ...metricAggConfigs, - { - id: 'grid', - enabled: true, - type: 'geotile_grid', - schema: 'segment', - params: { - field: this._descriptor.geoField, - useGeocentroid: true, - precision: precision, - }, - }, - ]; - } - _createHeatmapLayerDescriptor(options) { return HeatmapLayer.createDescriptor({ sourceDescriptor: this._descriptor, diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/geo_tile_utils.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/geo_tile_utils.js index da0bc1685f223..251e33b9579cb 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/geo_tile_utils.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/geo_tile_utils.js @@ -6,6 +6,7 @@ import _ from 'lodash'; import { DECIMAL_DEGREES_PRECISION } from '../../../../common/constants'; +import { clampToLatBounds } from '../../../elasticsearch_geo_utils'; const ZOOM_TILE_KEY_INDEX = 0; const X_TILE_KEY_INDEX = 1; @@ -87,7 +88,7 @@ function sec(value) { } function latitudeToTile(lat, tileCount) { - const radians = (lat * Math.PI) / 180; + const radians = (clampToLatBounds(lat) * Math.PI) / 180; const y = ((1 - Math.log(Math.tan(radians) + sec(radians)) / Math.PI) / 2) * tileCount; return Math.floor(y); } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/geo_tile_utils.test.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/geo_tile_utils.test.js index ae2623e168766..88a6ce048a178 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/geo_tile_utils.test.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/geo_tile_utils.test.js @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +jest.mock('../../../kibana_services', () => {}); + import { parseTileKey, getTileBoundingBox, expandToTileBoundaries } from './geo_tile_utils'; it('Should parse tile key', () => { diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/convert_to_lines.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/convert_to_lines.js index 2057949c30c88..96a7f50cdf523 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/convert_to_lines.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/convert_to_lines.js @@ -5,9 +5,11 @@ */ import _ from 'lodash'; +import { extractPropertiesFromBucket } from '../../util/es_agg_utils'; const LAT_INDEX = 0; const LON_INDEX = 1; +const PEW_PEW_BUCKET_KEYS_TO_IGNORE = ['key', 'sourceCentroid']; function parsePointFromKey(key) { const split = key.split(','); @@ -25,25 +27,16 @@ export function convertToLines(esResponse) { const dest = parsePointFromKey(destBucket.key); const sourceBuckets = _.get(destBucket, 'sourceGrid.buckets', []); for (let j = 0; j < sourceBuckets.length; j++) { - const { key, sourceCentroid, ...rest } = sourceBuckets[j]; - - // flatten metrics - Object.keys(rest).forEach(key => { - if (_.has(rest[key], 'value')) { - rest[key] = rest[key].value; - } - }); - + const sourceBucket = sourceBuckets[j]; + const sourceCentroid = sourceBucket.sourceCentroid; lineFeatures.push({ type: 'Feature', geometry: { type: 'LineString', coordinates: [[sourceCentroid.location.lon, sourceCentroid.location.lat], dest], }, - id: `${dest.join()},${key}`, - properties: { - ...rest, - }, + id: `${dest.join()},${sourceBucket.key}`, + properties: extractPropertiesFromBucket(sourceBucket, PEW_PEW_BUCKET_KEYS_TO_IGNORE), }); } } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/convert_to_lines.test.ts b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/convert_to_lines.test.ts new file mode 100644 index 0000000000000..5fbd5a3ad20c0 --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/convert_to_lines.test.ts @@ -0,0 +1,68 @@ +/* + * 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. + */ + +// @ts-ignore +import { convertToLines } from './convert_to_lines'; + +const esResponse = { + aggregations: { + destSplit: { + buckets: [ + { + key: '43.68389896117151, 10.39269994944334', + doc_count: 2, + sourceGrid: { + buckets: [ + { + key: '4/9/3', + doc_count: 1, + terms_of_Carrier: { + buckets: [ + { + key: 'ES-Air', + doc_count: 1, + }, + ], + }, + sourceCentroid: { + location: { + lat: 68.15180202014744, + lon: 33.46390150487423, + }, + count: 1, + }, + avg_of_FlightDelayMin: { + value: 3, + }, + }, + ], + }, + }, + ], + }, + }, +}; + +it('Should convert elasticsearch aggregation response into feature collection of lines', () => { + const geoJson = convertToLines(esResponse); + expect(geoJson.featureCollection.features.length).toBe(1); + expect(geoJson.featureCollection.features[0]).toEqual({ + geometry: { + coordinates: [ + [33.46390150487423, 68.15180202014744], + [10.39269994944334, 43.68389896117151], + ], + type: 'LineString', + }, + id: '10.39269994944334,43.68389896117151,4/9/3', + properties: { + avg_of_FlightDelayMin: 3, + doc_count: 1, + terms_of_Carrier: 'ES-Air', + }, + type: 'Feature', + }); +}); diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js index 176ab62baf98c..53536b11aaca6 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js @@ -20,7 +20,6 @@ import { i18n } from '@kbn/i18n'; import { SOURCE_DATA_ID_ORIGIN, ES_PEW_PEW, COUNT_PROP_NAME } from '../../../../common/constants'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; import { convertToLines } from './convert_to_lines'; -import { AggConfigs, Schemas } from 'ui/agg_types'; import { AbstractESAggSource } from '../es_agg_source'; import { DynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property'; import { COLOR_GRADIENTS } from '../../styles/color_utils'; @@ -28,8 +27,6 @@ import { indexPatterns } from '../../../../../../../../src/plugins/data/public'; const MAX_GEOTILE_LEVEL = 29; -const aggSchemas = new Schemas([AbstractESAggSource.METRIC_SCHEMA_CONFIG]); - export class ESPewPewSource extends AbstractESAggSource { static type = ES_PEW_PEW; static title = i18n.translate('xpack.maps.source.pewPewTitle', { @@ -170,9 +167,6 @@ export class ESPewPewSource extends AbstractESAggSource { async getGeoJsonWithMeta(layerName, searchFilters, registerCancelCallback) { const indexPattern = await this.getIndexPattern(); - const metricAggConfigs = this.createMetricAggConfigs(); - const aggConfigs = new AggConfigs(indexPattern, metricAggConfigs, aggSchemas.all); - const searchSource = await this._makeSearchSource(searchFilters, 0); searchSource.setField('aggs', { destSplit: { @@ -199,7 +193,7 @@ export class ESPewPewSource extends AbstractESAggSource { field: this._descriptor.sourceGeoField, }, }, - ...aggConfigs.toDsl(), + ...this.getValueAggsDsl(indexPattern), }, }, }, diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js index 288dd117da137..3533282436139 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js @@ -28,31 +28,7 @@ import { loadIndexSettings } from './load_index_settings'; import { DEFAULT_FILTER_BY_MAP_BOUNDS } from './constants'; import { ESDocField } from '../../fields/es_doc_field'; - -function getField(indexPattern, fieldName) { - const field = indexPattern.fields.getByName(fieldName); - if (!field) { - throw new Error( - i18n.translate('xpack.maps.source.esSearch.fieldNotFoundMsg', { - defaultMessage: `Unable to find '{fieldName}' in index-pattern '{indexPatternTitle}'.`, - values: { fieldName, indexPatternTitle: indexPattern.title }, - }) - ); - } - return field; -} - -function addFieldToDSL(dsl, field) { - return !field.scripted - ? { ...dsl, field: field.name } - : { - ...dsl, - script: { - source: field.script, - lang: field.lang, - }, - }; -} +import { getField, addFieldToDSL } from '../../util/es_agg_utils'; function getDocValueAndSourceFields(indexPattern, fieldNames) { const docValueFields = []; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js index d78d3038f870d..782f2845ceeff 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js @@ -18,7 +18,7 @@ import { AggConfigs } from 'ui/agg_types'; import { i18n } from '@kbn/i18n'; import uuid from 'uuid/v4'; import { copyPersistentState } from '../../reducers/util'; -import { ES_GEO_FIELD_TYPE, METRIC_TYPE } from '../../../common/constants'; +import { ES_GEO_FIELD_TYPE, AGG_TYPE } from '../../../common/constants'; import { DataRequestAbortError } from '../util/data_request'; import { expandToTileBoundaries } from './es_geo_grid_source/geo_tile_utils'; @@ -270,7 +270,7 @@ export class AbstractESSource extends AbstractVectorSource { // Do not use field formatters for counting metrics if ( metricField && - (metricField.type === METRIC_TYPE.COUNT || metricField.type === METRIC_TYPE.UNIQUE_COUNT) + (metricField.type === AGG_TYPE.COUNT || metricField.type === AGG_TYPE.UNIQUE_COUNT) ) { return null; } @@ -347,13 +347,16 @@ export class AbstractESSource extends AbstractVectorSource { } getValueSuggestions = async (fieldName, query) => { - if (!fieldName) { + // fieldName could be an aggregation so it needs to be unpacked to expose raw field. + const metricField = this.getMetricFields().find(field => field.getName() === fieldName); + const realFieldName = metricField ? metricField.getESDocFieldName() : fieldName; + if (!realFieldName) { return []; } try { const indexPattern = await this.getIndexPattern(); - const field = indexPattern.fields.getByName(fieldName); + const field = indexPattern.fields.getByName(realFieldName); return await autocompleteService.getValueSuggestions({ indexPattern, field, diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.js index 7d7a2e159d128..9cc2919404a94 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.js @@ -6,46 +6,25 @@ import _ from 'lodash'; -import { AggConfigs, Schemas } from 'ui/agg_types'; import { i18n } from '@kbn/i18n'; -import { - COUNT_PROP_LABEL, - DEFAULT_MAX_BUCKETS_LIMIT, - FIELD_ORIGIN, - METRIC_TYPE, -} from '../../../common/constants'; +import { DEFAULT_MAX_BUCKETS_LIMIT, FIELD_ORIGIN, AGG_TYPE } from '../../../common/constants'; import { ESDocField } from '../fields/es_doc_field'; import { AbstractESAggSource, AGG_DELIMITER } from './es_agg_source'; +import { getField, addFieldToDSL, extractPropertiesFromBucket } from '../util/es_agg_utils'; const TERMS_AGG_NAME = 'join'; const FIELD_NAME_PREFIX = '__kbnjoin__'; const GROUP_BY_DELIMITER = '_groupby_'; +const TERMS_BUCKET_KEYS_TO_IGNORE = ['key', 'doc_count']; -const aggSchemas = new Schemas([ - AbstractESAggSource.METRIC_SCHEMA_CONFIG, - { - group: 'buckets', - name: 'segment', - title: 'Terms', - aggFilter: 'terms', - min: 1, - max: 1, - }, -]); - -export function extractPropertiesMap(rawEsData, propertyNames, countPropertyName) { +export function extractPropertiesMap(rawEsData, countPropertyName) { const propertiesMap = new Map(); _.get(rawEsData, ['aggregations', TERMS_AGG_NAME, 'buckets'], []).forEach(termBucket => { - const properties = {}; + const properties = extractPropertiesFromBucket(termBucket, TERMS_BUCKET_KEYS_TO_IGNORE); if (countPropertyName) { properties[countPropertyName] = termBucket.doc_count; } - propertyNames.forEach(propertyName => { - if (_.has(termBucket, [propertyName, 'value'])) { - properties[propertyName] = _.get(termBucket, [propertyName, 'value']); - } - }); propertiesMap.set(termBucket.key.toString(), properties); }); return propertiesMap; @@ -90,15 +69,27 @@ export class ESTermSource extends AbstractESAggSource { formatMetricKey(aggType, fieldName) { const metricKey = - aggType !== METRIC_TYPE.COUNT ? `${aggType}${AGG_DELIMITER}${fieldName}` : aggType; + aggType !== AGG_TYPE.COUNT ? `${aggType}${AGG_DELIMITER}${fieldName}` : aggType; return `${FIELD_NAME_PREFIX}${metricKey}${GROUP_BY_DELIMITER}${ this._descriptor.indexPatternTitle }.${this._termField.getName()}`; } formatMetricLabel(type, fieldName) { - const metricLabel = type !== METRIC_TYPE.COUNT ? `${type} ${fieldName}` : COUNT_PROP_LABEL; - return `${metricLabel} of ${this._descriptor.indexPatternTitle}:${this._termField.getName()}`; + switch (type) { + case AGG_TYPE.COUNT: + return i18n.translate('xpack.maps.source.esJoin.countLabel', { + defaultMessage: `Count of {indexPatternTitle}`, + values: { indexPatternTitle: this._descriptor.indexPatternTitle }, + }); + case AGG_TYPE.TERMS: + return i18n.translate('xpack.maps.source.esJoin.topTermLabel', { + defaultMessage: `Top {fieldName}`, + values: { fieldName }, + }); + default: + return `${type} ${fieldName}`; + } } async getPropertiesMap(searchFilters, leftSourceName, leftFieldName, registerCancelCallback) { @@ -108,9 +99,14 @@ export class ESTermSource extends AbstractESAggSource { const indexPattern = await this.getIndexPattern(); const searchSource = await this._makeSearchSource(searchFilters, 0); - const configStates = this._makeAggConfigs(); - const aggConfigs = new AggConfigs(indexPattern, configStates, aggSchemas.all); - searchSource.setField('aggs', aggConfigs.toDsl()); + const termsField = getField(indexPattern, this._termField.getName()); + const termsAgg = { size: DEFAULT_MAX_BUCKETS_LIMIT }; + searchSource.setField('aggs', { + [TERMS_AGG_NAME]: { + terms: addFieldToDSL(termsAgg, termsField), + aggs: { ...this.getValueAggsDsl(indexPattern) }, + }, + }); const rawEsData = await this._runEsQuery({ requestId: this.getId(), @@ -120,19 +116,9 @@ export class ESTermSource extends AbstractESAggSource { requestDescription: this._getRequestDescription(leftSourceName, leftFieldName), }); - const metricPropertyNames = configStates - .filter(configState => { - return configState.schema === 'metric' && configState.type !== METRIC_TYPE.COUNT; - }) - .map(configState => { - return configState.id; - }); - const countConfigState = configStates.find(configState => { - return configState.type === METRIC_TYPE.COUNT; - }); - const countPropertyName = _.get(countConfigState, 'id'); + const countPropertyName = this.formatMetricKey(AGG_TYPE.COUNT); return { - propertiesMap: extractPropertiesMap(rawEsData, metricPropertyNames, countPropertyName), + propertiesMap: extractPropertiesMap(rawEsData, countPropertyName), }; } @@ -164,23 +150,6 @@ export class ESTermSource extends AbstractESAggSource { }); } - _makeAggConfigs() { - const metricAggConfigs = this.createMetricAggConfigs(); - return [ - ...metricAggConfigs, - { - id: TERMS_AGG_NAME, - enabled: true, - type: 'terms', - schema: 'segment', - params: { - field: this._termField.getName(), - size: DEFAULT_MAX_BUCKETS_LIMIT, - }, - }, - ]; - } - async getDisplayName() { //no need to localize. this is never rendered. return `es_table ${this._descriptor.indexPatternId}`; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.test.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.test.js index ffaaf2d705b5c..39cc301d458cb 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.test.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.test.js @@ -8,9 +8,6 @@ import { ESTermSource, extractPropertiesMap } from './es_term_source'; jest.mock('ui/new_platform'); jest.mock('../vector_layer', () => {}); -jest.mock('ui/agg_types', () => ({ - Schemas: function() {}, -})); jest.mock('ui/timefilter', () => {}); const indexPatternTitle = 'myIndex'; @@ -44,7 +41,7 @@ describe('getMetricFields', () => { expect(metrics[0].getAggType()).toEqual('count'); expect(metrics[0].getName()).toEqual('__kbnjoin__count_groupby_myIndex.myTermField'); - expect(await metrics[0].getLabel()).toEqual('count of myIndex:myTermField'); + expect(await metrics[0].getLabel()).toEqual('Count of myIndex'); }); it('should remove incomplete metric configurations', async () => { @@ -65,84 +62,13 @@ describe('getMetricFields', () => { expect(metrics[1].getAggType()).toEqual('count'); expect(metrics[1].getName()).toEqual('__kbnjoin__count_groupby_myIndex.myTermField'); - expect(await metrics[1].getLabel()).toEqual('count of myIndex:myTermField'); - }); -}); - -describe('_makeAggConfigs', () => { - describe('no metrics', () => { - let aggConfigs; - beforeAll(() => { - const source = new ESTermSource({ - indexPatternTitle: indexPatternTitle, - term: termFieldName, - }); - aggConfigs = source._makeAggConfigs(); - }); - - it('should make default "count" metric agg config', () => { - expect(aggConfigs.length).toBe(2); - expect(aggConfigs[0]).toEqual({ - id: '__kbnjoin__count_groupby_myIndex.myTermField', - enabled: true, - type: 'count', - schema: 'metric', - params: {}, - }); - }); - - it('should make "terms" buckets agg config', () => { - expect(aggConfigs.length).toBe(2); - expect(aggConfigs[1]).toEqual({ - id: 'join', - enabled: true, - type: 'terms', - schema: 'segment', - params: { - field: termFieldName, - size: 10000, - }, - }); - }); - }); - - describe('metrics', () => { - let aggConfigs; - beforeAll(() => { - const source = new ESTermSource({ - indexPatternTitle: indexPatternTitle, - term: 'myTermField', - metrics: metricExamples, - }); - aggConfigs = source._makeAggConfigs(); - }); - - it('should ignore invalid metrics configs', () => { - expect(aggConfigs.length).toBe(3); - }); - - it('should make agg config for each valid metric', () => { - expect(aggConfigs[0]).toEqual({ - id: '__kbnjoin__sum_of_myFieldGettingSummed_groupby_myIndex.myTermField', - enabled: true, - type: 'sum', - schema: 'metric', - params: { - field: sumFieldName, - }, - }); - expect(aggConfigs[1]).toEqual({ - id: '__kbnjoin__count_groupby_myIndex.myTermField', - enabled: true, - type: 'count', - schema: 'metric', - params: {}, - }); - }); + expect(await metrics[1].getLabel()).toEqual('Count of myIndex'); }); }); describe('extractPropertiesMap', () => { + const minPropName = + '__kbnjoin__min_of_avlAirTemp_groupby_kibana_sample_data_ky_avl.kytcCountyNmbr'; const responseWithNumberTypes = { aggregations: { join: { @@ -150,14 +76,14 @@ describe('extractPropertiesMap', () => { { key: 109, doc_count: 1130, - '__kbnjoin__min_of_avlAirTemp_groupby_kibana_sample_data_ky_avl.kytcCountyNmbr': { + [minPropName]: { value: 36, }, }, { key: 62, doc_count: 448, - '__kbnjoin__min_of_avlAirTemp_groupby_kibana_sample_data_ky_avl.kytcCountyNmbr': { + [minPropName]: { value: 0, }, }, @@ -166,11 +92,10 @@ describe('extractPropertiesMap', () => { }, }; const countPropName = '__kbnjoin__count_groupby_kibana_sample_data_ky_avl.kytcCountyNmbr'; - const minPropName = - '__kbnjoin__min_of_avlAirTemp_groupby_kibana_sample_data_ky_avl.kytcCountyNmbr'; + let propertiesMap; beforeAll(() => { - propertiesMap = extractPropertiesMap(responseWithNumberTypes, [minPropName], countPropName); + propertiesMap = extractPropertiesMap(responseWithNumberTypes, countPropName); }); it('should create key for each join term', () => { diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_size_property.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_size_property.js index e137e15730827..dfc5c530cc90f 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_size_property.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_size_property.js @@ -43,16 +43,8 @@ function getSymbolSizeIcons() { } export class DynamicSizeProperty extends DynamicStyleProperty { - constructor( - options, - styleName, - field, - getFieldMeta, - getFieldFormatter, - getValueSuggestions, - isSymbolizedAsIcon - ) { - super(options, styleName, field, getFieldMeta, getFieldFormatter, getValueSuggestions); + constructor(options, styleName, field, getFieldMeta, getFieldFormatter, isSymbolizedAsIcon) { + super(options, styleName, field, getFieldMeta, getFieldFormatter); this._isSymbolizedAsIcon = isSymbolizedAsIcon; } diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.js index ef19e9b23b10d..af78c4c0e461e 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.js @@ -13,21 +13,22 @@ import React from 'react'; import { OrdinalLegend } from './components/ordinal_legend'; import { CategoricalLegend } from './components/categorical_legend'; import { OrdinalFieldMetaOptionsPopover } from '../components/ordinal_field_meta_options_popover'; +import { ESAggMetricField } from '../../../fields/es_agg_field'; export class DynamicStyleProperty extends AbstractStyleProperty { static type = STYLE_TYPE.DYNAMIC; - constructor(options, styleName, field, getFieldMeta, getFieldFormatter, source) { + constructor(options, styleName, field, getFieldMeta, getFieldFormatter) { super(options, styleName); this._field = field; this._getFieldMeta = getFieldMeta; this._getFieldFormatter = getFieldFormatter; - this._source = source; } getValueSuggestions = query => { const fieldName = this.getFieldName(); - return this._source && fieldName ? this._source.getValueSuggestions(fieldName, query) : []; + const fieldSource = this.getFieldSource(); + return fieldSource && fieldName ? fieldSource.getValueSuggestions(fieldName, query) : []; }; getFieldMeta() { @@ -38,6 +39,10 @@ export class DynamicStyleProperty extends AbstractStyleProperty { return this._field; } + getFieldSource() { + return this._field ? this._field.getSource() : null; + } + getFieldName() { return this._field ? this._field.getName() : ''; } @@ -180,9 +185,10 @@ export class DynamicStyleProperty extends AbstractStyleProperty { } _pluckOrdinalStyleMetaFromFieldMetaData(fieldMetaData) { - const realFieldName = this._field.getESDocFieldName - ? this._field.getESDocFieldName() - : this._field.getName(); + const realFieldName = + this._field instanceof ESAggMetricField + ? this._field.getESDocFieldName() + : this._field.getName(); const stats = fieldMetaData[realFieldName]; if (!stats) { return null; @@ -203,12 +209,15 @@ export class DynamicStyleProperty extends AbstractStyleProperty { } _pluckCategoricalStyleMetaFromFieldMetaData(fieldMetaData) { - const name = this.getField().getName(); - if (!fieldMetaData[name] || !fieldMetaData[name].buckets) { + const realFieldName = + this._field instanceof ESAggMetricField + ? this._field.getESDocFieldName() + : this._field.getName(); + if (!fieldMetaData[realFieldName] || !fieldMetaData[realFieldName].buckets) { return null; } - const ordered = fieldMetaData[name].buckets.map(bucket => { + const ordered = fieldMetaData[realFieldName].buckets.map(bucket => { return { key: bucket.key, count: bucket.doc_count, diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.js index 62651fdd702d6..053aa114d94ae 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.js @@ -625,7 +625,6 @@ export class VectorStyle extends AbstractStyle { field, this._getFieldMeta, this._getFieldFormatter, - this._source, isSymbolizedAsIcon ); } else { @@ -645,8 +644,7 @@ export class VectorStyle extends AbstractStyle { styleName, field, this._getFieldMeta, - this._getFieldFormatter, - this._source + this._getFieldFormatter ); } else { throw new Error(`${descriptor} not implemented`); @@ -678,8 +676,7 @@ export class VectorStyle extends AbstractStyle { VECTOR_STYLES.LABEL_TEXT, field, this._getFieldMeta, - this._getFieldFormatter, - this._source + this._getFieldFormatter ); } else { throw new Error(`${descriptor} not implemented`); @@ -698,8 +695,7 @@ export class VectorStyle extends AbstractStyle { VECTOR_STYLES.ICON, field, this._getFieldMeta, - this._getFieldFormatter, - this._source + this._getFieldFormatter ); } else { throw new Error(`${descriptor} not implemented`); diff --git a/x-pack/legacy/plugins/maps/public/layers/tooltips/es_aggmetric_tooltip_property.js b/x-pack/legacy/plugins/maps/public/layers/tooltips/es_aggmetric_tooltip_property.js index 7cfb60910c155..229c84fe234bd 100644 --- a/x-pack/legacy/plugins/maps/public/layers/tooltips/es_aggmetric_tooltip_property.js +++ b/x-pack/legacy/plugins/maps/public/layers/tooltips/es_aggmetric_tooltip_property.js @@ -5,7 +5,7 @@ */ import { ESTooltipProperty } from './es_tooltip_property'; -import { METRIC_TYPE } from '../../../common/constants'; +import { AGG_TYPE } from '../../../common/constants'; export class ESAggMetricTooltipProperty extends ESTooltipProperty { constructor(propertyKey, propertyName, rawValue, indexPattern, metricField) { @@ -22,8 +22,8 @@ export class ESAggMetricTooltipProperty extends ESTooltipProperty { return '-'; } if ( - this._metricField.getAggType() === METRIC_TYPE.COUNT || - this._metricField.getAggType() === METRIC_TYPE.UNIQUE_COUNT + this._metricField.getAggType() === AGG_TYPE.COUNT || + this._metricField.getAggType() === AGG_TYPE.UNIQUE_COUNT ) { return this._rawValue; } diff --git a/x-pack/legacy/plugins/maps/public/layers/util/es_agg_utils.test.ts b/x-pack/legacy/plugins/maps/public/layers/util/es_agg_utils.test.ts new file mode 100644 index 0000000000000..201d6907981a2 --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/util/es_agg_utils.test.ts @@ -0,0 +1,37 @@ +/* + * 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 { extractPropertiesFromBucket } from './es_agg_utils'; + +describe('extractPropertiesFromBucket', () => { + test('Should ignore specified keys', () => { + const properties = extractPropertiesFromBucket({ key: '4/4/6' }, ['key']); + expect(properties).toEqual({}); + }); + + test('Should extract metric aggregation values', () => { + const properties = extractPropertiesFromBucket({ avg_of_bytes: { value: 5359 } }); + expect(properties).toEqual({ + avg_of_bytes: 5359, + }); + }); + + test('Should extract bucket aggregation values', () => { + const properties = extractPropertiesFromBucket({ + 'terms_of_machine.os.keyword': { + buckets: [ + { + key: 'win xp', + doc_count: 16, + }, + ], + }, + }); + expect(properties).toEqual({ + 'terms_of_machine.os.keyword': 'win xp', + }); + }); +}); diff --git a/x-pack/legacy/plugins/maps/public/layers/util/es_agg_utils.ts b/x-pack/legacy/plugins/maps/public/layers/util/es_agg_utils.ts new file mode 100644 index 0000000000000..7af176acfaf46 --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/util/es_agg_utils.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { i18n } from '@kbn/i18n'; +import _ from 'lodash'; +import { IndexPattern, IFieldType } from '../../../../../../../src/plugins/data/public'; + +export function getField(indexPattern: IndexPattern, fieldName: string) { + const field = indexPattern.fields.getByName(fieldName); + if (!field) { + throw new Error( + i18n.translate('xpack.maps.source.esSearch.fieldNotFoundMsg', { + defaultMessage: `Unable to find '{fieldName}' in index-pattern '{indexPatternTitle}'.`, + values: { fieldName, indexPatternTitle: indexPattern.title }, + }) + ); + } + return field; +} + +export function addFieldToDSL(dsl: object, field: IFieldType) { + return !field.scripted + ? { ...dsl, field: field.name } + : { + ...dsl, + script: { + source: field.script, + lang: field.lang, + }, + }; +} + +export function extractPropertiesFromBucket(bucket: any, ignoreKeys: string[] = []) { + const properties: Record = {}; + for (const key in bucket) { + if (ignoreKeys.includes(key) || !bucket.hasOwnProperty(key)) { + continue; + } + + if (_.has(bucket[key], 'value')) { + properties[key] = bucket[key].value; + } else if (_.has(bucket[key], 'buckets')) { + properties[key] = _.get(bucket[key], 'buckets[0].key'); + } else { + properties[key] = bucket[key]; + } + } + return properties; +} diff --git a/x-pack/legacy/plugins/maps/public/layers/util/is_metric_countable.js b/x-pack/legacy/plugins/maps/public/layers/util/is_metric_countable.js index 54d8794b1e3cf..69ccb8890d10c 100644 --- a/x-pack/legacy/plugins/maps/public/layers/util/is_metric_countable.js +++ b/x-pack/legacy/plugins/maps/public/layers/util/is_metric_countable.js @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { METRIC_TYPE } from '../../../common/constants'; +import { AGG_TYPE } from '../../../common/constants'; export function isMetricCountable(aggType) { - return [METRIC_TYPE.COUNT, METRIC_TYPE.SUM, METRIC_TYPE.UNIQUE_COUNT].includes(aggType); + return [AGG_TYPE.COUNT, AGG_TYPE.SUM, AGG_TYPE.UNIQUE_COUNT].includes(aggType); } diff --git a/x-pack/legacy/plugins/maps/public/layers/vector_layer.js b/x-pack/legacy/plugins/maps/public/layers/vector_layer.js index 1698d52ea4406..e1a30c8aef1d3 100644 --- a/x-pack/legacy/plugins/maps/public/layers/vector_layer.js +++ b/x-pack/legacy/plugins/maps/public/layers/vector_layer.js @@ -365,8 +365,10 @@ export class VectorLayer extends AbstractLayer { onLoadError, registerCancelCallback, dataFilters, + isRequestStillActive, }) { - const requestToken = Symbol(`layer-${this.getId()}-${SOURCE_DATA_ID_ORIGIN}`); + const dataRequestId = SOURCE_DATA_ID_ORIGIN; + const requestToken = Symbol(`layer-${this.getId()}-${dataRequestId}`); const searchFilters = this._getSearchFilters(dataFilters); const prevDataRequest = this.getSourceDataRequest(); const canSkipFetch = await canSkipSourceUpdate({ @@ -382,22 +384,25 @@ export class VectorLayer extends AbstractLayer { } try { - startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, searchFilters); + startLoading(dataRequestId, requestToken, searchFilters); const layerName = await this.getDisplayName(); const { data: sourceFeatureCollection, meta } = await this._source.getGeoJsonWithMeta( layerName, searchFilters, - registerCancelCallback.bind(null, requestToken) + registerCancelCallback.bind(null, requestToken), + () => { + return isRequestStillActive(dataRequestId, requestToken); + } ); const layerFeatureCollection = assignFeatureIds(sourceFeatureCollection); - stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, layerFeatureCollection, meta); + stopLoading(dataRequestId, requestToken, layerFeatureCollection, meta); return { refreshed: true, featureCollection: layerFeatureCollection, }; } catch (error) { if (!(error instanceof DataRequestAbortError)) { - onLoadError(SOURCE_DATA_ID_ORIGIN, requestToken, error.message); + onLoadError(dataRequestId, requestToken, error.message); } return { refreshed: false, diff --git a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js b/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js index d1048a759beca..4074344916390 100644 --- a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js +++ b/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js @@ -125,6 +125,21 @@ export const getRefreshConfig = ({ map }) => { export const getRefreshTimerLastTriggeredAt = ({ map }) => map.mapState.refreshTimerLastTriggeredAt; +function getLayerDescriptor(state = {}, layerId) { + const layerListRaw = getLayerListRaw(state); + return layerListRaw.find(layer => layer.id === layerId); +} + +export function getDataRequestDescriptor(state = {}, layerId, dataId) { + const layerDescriptor = getLayerDescriptor(state, layerId); + if (!layerDescriptor || !layerDescriptor.__dataRequests) { + return; + } + return _.get(layerDescriptor, '__dataRequests', []).find(dataRequest => { + return dataRequest.dataId === dataId; + }); +} + export const getDataFilters = createSelector( getMapExtent, getMapBuffer, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 4a627d48c3cf0..3c7d0ce47acb7 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7263,7 +7263,6 @@ "xpack.maps.source.esGrid.finestDropdownOption": "最も細かい", "xpack.maps.source.esGrid.geospatialFieldLabel": "地理空間フィールド", "xpack.maps.source.esGrid.indexPatternLabel": "インデックスパターン", - "xpack.maps.source.esGrid.inspectorDescription": "Elasticsearch ジオグリッド集約リクエスト", "xpack.maps.source.esGrid.metricsLabel": "メトリック", "xpack.maps.source.esGrid.noIndexPatternErrorMessage": "インデックスパターン {id} が見つかりません", "xpack.maps.source.esGrid.resolutionParamErrorMessage": "グリッド解像度パラメーターが認識されません: {resolution}", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index e0ef4a7a1ebdb..b262be626aa53 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7263,7 +7263,6 @@ "xpack.maps.source.esGrid.finestDropdownOption": "最精致化", "xpack.maps.source.esGrid.geospatialFieldLabel": "地理空间字段", "xpack.maps.source.esGrid.indexPatternLabel": "索引模式", - "xpack.maps.source.esGrid.inspectorDescription": "Elasticsearch 地理网格聚合请求", "xpack.maps.source.esGrid.metricsLabel": "指标", "xpack.maps.source.esGrid.noIndexPatternErrorMessage": "找不到索引模式 {id}", "xpack.maps.source.esGrid.resolutionParamErrorMessage": "无法识别网格分辨率参数:{resolution}", From 47aa5b46df1dcafe0cf26043e00cb113da6bad79 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Wed, 26 Feb 2020 15:59:22 +0100 Subject: [PATCH 089/123] Saved query management: Discard pending listing requests (#58433) * discard pending listing requests * consolidate requests --- .../saved_query/saved_query_service.test.ts | 27 +++++++++++++++---- .../query/saved_query/saved_query_service.ts | 13 +++++---- .../data/public/query/saved_query/types.ts | 2 +- .../saved_query_management_component.tsx | 20 +++++++++++--- 4 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/plugins/data/public/query/saved_query/saved_query_service.test.ts b/src/plugins/data/public/query/saved_query/saved_query_service.test.ts index a6b8de32a00bd..c983cc4ea8fc5 100644 --- a/src/plugins/data/public/query/saved_query/saved_query_service.test.ts +++ b/src/plugins/data/public/query/saved_query/saved_query_service.test.ts @@ -169,15 +169,27 @@ describe('saved query service', () => { it('should find and return saved queries without search text or pagination parameters', async () => { mockSavedObjectsClient.find.mockReturnValue({ savedObjects: [{ id: 'foo', attributes: savedQueryAttributes }], + total: 5, }); const response = await findSavedQueries(); - expect(response).toEqual([{ id: 'foo', attributes: savedQueryAttributes }]); + expect(response.queries).toEqual([{ id: 'foo', attributes: savedQueryAttributes }]); + }); + + it('should return the total count along with the requested queries', async () => { + mockSavedObjectsClient.find.mockReturnValue({ + savedObjects: [{ id: 'foo', attributes: savedQueryAttributes }], + total: 5, + }); + + const response = await findSavedQueries(); + expect(response.total).toEqual(5); }); it('should find and return saved queries with search text matching the title field', async () => { mockSavedObjectsClient.find.mockReturnValue({ savedObjects: [{ id: 'foo', attributes: savedQueryAttributes }], + total: 5, }); const response = await findSavedQueries('foo'); expect(mockSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -188,7 +200,7 @@ describe('saved query service', () => { sortField: '_score', type: 'query', }); - expect(response).toEqual([{ id: 'foo', attributes: savedQueryAttributes }]); + expect(response.queries).toEqual([{ id: 'foo', attributes: savedQueryAttributes }]); }); it('should find and return parsed filters and timefilters items', async () => { const serializedSavedQueryAttributesWithFilters = { @@ -198,16 +210,20 @@ describe('saved query service', () => { }; mockSavedObjectsClient.find.mockReturnValue({ savedObjects: [{ id: 'foo', attributes: serializedSavedQueryAttributesWithFilters }], + total: 5, }); const response = await findSavedQueries('bar'); - expect(response).toEqual([{ id: 'foo', attributes: savedQueryAttributesWithFilters }]); + expect(response.queries).toEqual([ + { id: 'foo', attributes: savedQueryAttributesWithFilters }, + ]); }); it('should return an array of saved queries', async () => { mockSavedObjectsClient.find.mockReturnValue({ savedObjects: [{ id: 'foo', attributes: savedQueryAttributes }], + total: 5, }); const response = await findSavedQueries(); - expect(response).toEqual( + expect(response.queries).toEqual( expect.objectContaining([ { attributes: { @@ -226,6 +242,7 @@ describe('saved query service', () => { { id: 'foo', attributes: savedQueryAttributes }, { id: 'bar', attributes: savedQueryAttributesBar }, ], + total: 5, }); const response = await findSavedQueries(undefined, 2, 1); expect(mockSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -236,7 +253,7 @@ describe('saved query service', () => { sortField: '_score', type: 'query', }); - expect(response).toEqual( + expect(response.queries).toEqual( expect.objectContaining([ { attributes: { diff --git a/src/plugins/data/public/query/saved_query/saved_query_service.ts b/src/plugins/data/public/query/saved_query/saved_query_service.ts index 80dec1c9373ea..4d3a8f441ce5e 100644 --- a/src/plugins/data/public/query/saved_query/saved_query_service.ts +++ b/src/plugins/data/public/query/saved_query/saved_query_service.ts @@ -95,7 +95,7 @@ export const createSavedQueryService = ( searchText: string = '', perPage: number = 50, activePage: number = 1 - ): Promise => { + ): Promise<{ total: number; queries: SavedQuery[] }> => { const response = await savedObjectsClient.find({ type: 'query', search: searchText, @@ -105,10 +105,13 @@ export const createSavedQueryService = ( page: activePage, }); - return response.savedObjects.map( - (savedObject: { id: string; attributes: SerializedSavedQueryAttributes }) => - parseSavedQueryObject(savedObject) - ); + return { + total: response.total, + queries: response.savedObjects.map( + (savedObject: { id: string; attributes: SerializedSavedQueryAttributes }) => + parseSavedQueryObject(savedObject) + ), + }; }; const getSavedQuery = async (id: string): Promise => { diff --git a/src/plugins/data/public/query/saved_query/types.ts b/src/plugins/data/public/query/saved_query/types.ts index d05eada7b29e6..6ac5e51d5c312 100644 --- a/src/plugins/data/public/query/saved_query/types.ts +++ b/src/plugins/data/public/query/saved_query/types.ts @@ -46,7 +46,7 @@ export interface SavedQueryService { searchText?: string, perPage?: number, activePage?: number - ) => Promise; + ) => Promise<{ total: number; queries: SavedQuery[] }>; getSavedQuery: (id: string) => Promise; deleteSavedQuery: (id: string) => Promise<{}>; getSavedQueryCount: () => Promise; diff --git a/src/plugins/data/public/ui/saved_query_management/saved_query_management_component.tsx b/src/plugins/data/public/ui/saved_query_management/saved_query_management_component.tsx index 2a11531ee336d..9347ef5974261 100644 --- a/src/plugins/data/public/ui/saved_query_management/saved_query_management_component.tsx +++ b/src/plugins/data/public/ui/saved_query_management/saved_query_management_component.tsx @@ -33,7 +33,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React, { FunctionComponent, useEffect, useState, Fragment } from 'react'; +import React, { FunctionComponent, useEffect, useState, Fragment, useRef } from 'react'; import { sortBy } from 'lodash'; import { SavedQuery, SavedQueryService } from '../..'; import { SavedQueryListItem } from './saved_query_list_item'; @@ -62,14 +62,25 @@ export const SavedQueryManagementComponent: FunctionComponent = ({ const [savedQueries, setSavedQueries] = useState([] as SavedQuery[]); const [count, setTotalCount] = useState(0); const [activePage, setActivePage] = useState(0); + const cancelPendingListingRequest = useRef<() => void>(() => {}); useEffect(() => { const fetchCountAndSavedQueries = async () => { - const savedQueryCount = await savedQueryService.getSavedQueryCount(); - setTotalCount(savedQueryCount); + cancelPendingListingRequest.current(); + let requestGotCancelled = false; + cancelPendingListingRequest.current = () => { + requestGotCancelled = true; + }; + + const { + total: savedQueryCount, + queries: savedQueryItems, + } = await savedQueryService.findSavedQueries('', perPage, activePage + 1); + + if (requestGotCancelled) return; - const savedQueryItems = await savedQueryService.findSavedQueries('', perPage, activePage + 1); const sortedSavedQueryItems = sortBy(savedQueryItems, 'attributes.title'); + setTotalCount(savedQueryCount); setSavedQueries(sortedSavedQueryItems); }; if (isOpen) { @@ -103,6 +114,7 @@ export const SavedQueryManagementComponent: FunctionComponent = ({ ); const onDeleteSavedQuery = async (savedQuery: SavedQuery) => { + cancelPendingListingRequest.current(); setSavedQueries( savedQueries.filter(currentSavedQuery => currentSavedQuery.id !== savedQuery.id) ); From 8524303b6e5cac434353d57700a31e907ab93f5a Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Wed, 26 Feb 2020 16:22:35 +0100 Subject: [PATCH 090/123] Allow savedObjects types registration from NP (#57430) * expose `registerType` API * expose `getTypeRegistry` API * change SavedObjectMigrationFn signature to add context * fix exported types * update generated doc * update migration documentation * fix legacy service test * fix typings * update service setup description * add saved_objects server folder convention * fix unit test * documentation NITs * add typeRegistry to SavedObjectClientWrapperOptions --- ...-plugin-server.isavedobjecttyperegistry.md | 13 ++ .../core/server/kibana-plugin-server.md | 7 +- ...-server.savedobjectmigrationcontext.log.md | 13 ++ ...ugin-server.savedobjectmigrationcontext.md | 20 ++ ...na-plugin-server.savedobjectmigrationfn.md | 21 +- ...server.savedobjectsclientwrapperoptions.md | 1 + ...bjectsclientwrapperoptions.typeregistry.md | 11 ++ ...-plugin-server.savedobjectsservicesetup.md | 24 ++- ...r.savedobjectsservicesetup.registertype.md | 60 ++++++ ...avedobjectsservicestart.gettyperegistry.md | 13 ++ ...-plugin-server.savedobjectsservicestart.md | 1 + ...ver.savedobjecttyperegistry.getalltypes.md | 17 ++ ...server.savedobjecttyperegistry.getindex.md | 24 +++ ...-server.savedobjecttyperegistry.gettype.md | 24 +++ ...server.savedobjecttyperegistry.ishidden.md | 24 +++ ...dobjecttyperegistry.isnamespaceagnostic.md | 24 +++ ...a-plugin-server.savedobjecttyperegistry.md | 25 +++ ...er.savedobjecttyperegistry.registertype.md | 24 +++ src/core/CONVENTIONS.md | 43 +++++ src/core/MIGRATION.md | 3 + src/core/MIGRATION_EXAMPLES.md | 181 ++++++++++++++++++ src/core/server/index.ts | 2 + src/core/server/legacy/legacy_service.ts | 3 +- src/core/server/mocks.ts | 8 +- src/core/server/plugins/plugin_context.ts | 2 + .../__snapshots__/utils.test.ts.snap | 6 +- src/core/server/saved_objects/index.ts | 6 +- .../migrations/core/document_migrator.test.ts | 2 +- .../migrations/core/document_migrator.ts | 3 +- .../server/saved_objects/migrations/index.ts | 6 +- .../server/saved_objects/migrations/types.ts | 33 +++- .../saved_objects_service.mock.ts | 5 +- .../saved_objects_service.test.ts | 13 +- .../saved_objects/saved_objects_service.ts | 95 ++++++--- .../saved_objects_type_registry.mock.ts | 5 +- .../saved_objects_type_registry.ts | 13 +- .../lib/scoped_client_provider.test.js | 12 ++ .../service/lib/scoped_client_provider.ts | 15 +- src/core/server/saved_objects/types.ts | 21 +- src/core/server/saved_objects/utils.test.ts | 47 ++++- src/core/server/saved_objects/utils.ts | 20 +- src/core/server/server.api.md | 20 +- src/legacy/server/kbn_server.d.ts | 1 - .../saved_objects/saved_objects_mixin.js | 2 +- .../saved_objects/saved_objects_mixin.test.js | 7 +- 45 files changed, 841 insertions(+), 79 deletions(-) create mode 100644 docs/development/core/server/kibana-plugin-server.isavedobjecttyperegistry.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjectmigrationcontext.log.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjectmigrationcontext.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.typeregistry.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.registertype.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.gettyperegistry.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.getalltypes.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.getindex.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.gettype.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.ishidden.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.isnamespaceagnostic.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.registertype.md diff --git a/docs/development/core/server/kibana-plugin-server.isavedobjecttyperegistry.md b/docs/development/core/server/kibana-plugin-server.isavedobjecttyperegistry.md new file mode 100644 index 0000000000000..bbcba50c81027 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.isavedobjecttyperegistry.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [ISavedObjectTypeRegistry](./kibana-plugin-server.isavedobjecttyperegistry.md) + +## ISavedObjectTypeRegistry type + +See [SavedObjectTypeRegistry](./kibana-plugin-server.savedobjecttyperegistry.md) for documentation. + +Signature: + +```typescript +export declare type ISavedObjectTypeRegistry = Pick; +``` diff --git a/docs/development/core/server/kibana-plugin-server.md b/docs/development/core/server/kibana-plugin-server.md index 9ec443d6482e8..15a1fd0506256 100644 --- a/docs/development/core/server/kibana-plugin-server.md +++ b/docs/development/core/server/kibana-plugin-server.md @@ -27,6 +27,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md) | | | [SavedObjectsRepository](./kibana-plugin-server.savedobjectsrepository.md) | | | [SavedObjectsSerializer](./kibana-plugin-server.savedobjectsserializer.md) | A serializer that can be used to manually convert [raw](./kibana-plugin-server.savedobjectsrawdoc.md) or [sanitized](./kibana-plugin-server.savedobjectsanitizeddoc.md) documents to the other kind. | +| [SavedObjectTypeRegistry](./kibana-plugin-server.savedobjecttyperegistry.md) | Registry holding information about all the registered [saved object types](./kibana-plugin-server.savedobjectstype.md). | | [ScopedClusterClient](./kibana-plugin-server.scopedclusterclient.md) | Serves the same purpose as "normal" ClusterClient but exposes additional callAsCurrentUser method that doesn't use credentials of the Kibana internal user (as callAsInternalUser does) to request Elasticsearch API, but rather passes HTTP headers extracted from the current user request to the API.See [ScopedClusterClient](./kibana-plugin-server.scopedclusterclient.md). | ## Enumerations @@ -108,6 +109,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [RouteValidatorOptions](./kibana-plugin-server.routevalidatoroptions.md) | Additional options for the RouteValidator class to modify its default behaviour. | | [SavedObject](./kibana-plugin-server.savedobject.md) | | | [SavedObjectAttributes](./kibana-plugin-server.savedobjectattributes.md) | The data for a Saved Object is stored as an object in the attributes property. | +| [SavedObjectMigrationContext](./kibana-plugin-server.savedobjectmigrationcontext.md) | Migration context provided when invoking a [migration handler](./kibana-plugin-server.savedobjectmigrationfn.md) | | [SavedObjectMigrationMap](./kibana-plugin-server.savedobjectmigrationmap.md) | A map of [migration functions](./kibana-plugin-server.savedobjectmigrationfn.md) to be used for a given type. The map's keys must be valid semver versions.For a given document, only migrations with a higher version number than that of the document will be applied. Migrations are executed in order, starting from the lowest version and ending with the highest one. | | [SavedObjectReference](./kibana-plugin-server.savedobjectreference.md) | A reference to another saved object. | | [SavedObjectsBaseOptions](./kibana-plugin-server.savedobjectsbaseoptions.md) | | @@ -143,7 +145,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [SavedObjectsRawDoc](./kibana-plugin-server.savedobjectsrawdoc.md) | A raw document as represented directly in the saved object index. | | [SavedObjectsRepositoryFactory](./kibana-plugin-server.savedobjectsrepositoryfactory.md) | Factory provided when invoking a [client factory provider](./kibana-plugin-server.savedobjectsclientfactoryprovider.md) See [SavedObjectsServiceSetup.setClientFactoryProvider](./kibana-plugin-server.savedobjectsservicesetup.setclientfactoryprovider.md) | | [SavedObjectsResolveImportErrorsOptions](./kibana-plugin-server.savedobjectsresolveimporterrorsoptions.md) | Options to control the "resolve import" operation. | -| [SavedObjectsServiceSetup](./kibana-plugin-server.savedobjectsservicesetup.md) | Saved Objects is Kibana's data persistence mechanism allowing plugins to use Elasticsearch for storing and querying state. The SavedObjectsServiceSetup API exposes methods for creating and registering Saved Object client wrappers. | +| [SavedObjectsServiceSetup](./kibana-plugin-server.savedobjectsservicesetup.md) | Saved Objects is Kibana's data persistence mechanism allowing plugins to use Elasticsearch for storing and querying state. The SavedObjectsServiceSetup API exposes methods for registering Saved Object types, creating and registering Saved Object client wrappers and factories. | | [SavedObjectsServiceStart](./kibana-plugin-server.savedobjectsservicestart.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing and querying state. The SavedObjectsServiceStart API provides a scoped Saved Objects client for interacting with Saved Objects. | | [SavedObjectsType](./kibana-plugin-server.savedobjectstype.md) | | | [SavedObjectsTypeMappingDefinition](./kibana-plugin-server.savedobjectstypemappingdefinition.md) | Describe a saved object type mapping. | @@ -195,6 +197,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [ICustomClusterClient](./kibana-plugin-server.icustomclusterclient.md) | Represents an Elasticsearch cluster API client created by a plugin. It allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via asScoped(...)).See [ClusterClient](./kibana-plugin-server.clusterclient.md). | | [IsAuthenticated](./kibana-plugin-server.isauthenticated.md) | Returns authentication status for a request. | | [ISavedObjectsRepository](./kibana-plugin-server.isavedobjectsrepository.md) | See [SavedObjectsRepository](./kibana-plugin-server.savedobjectsrepository.md) | +| [ISavedObjectTypeRegistry](./kibana-plugin-server.isavedobjecttyperegistry.md) | See [SavedObjectTypeRegistry](./kibana-plugin-server.savedobjecttyperegistry.md) for documentation. | | [IScopedClusterClient](./kibana-plugin-server.iscopedclusterclient.md) | Serves the same purpose as "normal" ClusterClient but exposes additional callAsCurrentUser method that doesn't use credentials of the Kibana internal user (as callAsInternalUser does) to request Elasticsearch API, but rather passes HTTP headers extracted from the current user request to the API.See [ScopedClusterClient](./kibana-plugin-server.scopedclusterclient.md). | | [KibanaRequestRouteOptions](./kibana-plugin-server.kibanarequestrouteoptions.md) | Route options: If 'GET' or 'OPTIONS' method, body options won't be returned. | | [KibanaResponseFactory](./kibana-plugin-server.kibanaresponsefactory.md) | Creates an object containing request response payload, HTTP headers, error details, and other data transmitted to the client. | @@ -226,7 +229,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [RouteValidatorFullConfig](./kibana-plugin-server.routevalidatorfullconfig.md) | Route validations config and options merged into one object | | [SavedObjectAttribute](./kibana-plugin-server.savedobjectattribute.md) | Type definition for a Saved Object attribute value | | [SavedObjectAttributeSingle](./kibana-plugin-server.savedobjectattributesingle.md) | Don't use this type, it's simply a helper type for [SavedObjectAttribute](./kibana-plugin-server.savedobjectattribute.md) | -| [SavedObjectMigrationFn](./kibana-plugin-server.savedobjectmigrationfn.md) | A migration function defined for a [saved objects type](./kibana-plugin-server.savedobjectstype.md) used to migrate it's | +| [SavedObjectMigrationFn](./kibana-plugin-server.savedobjectmigrationfn.md) | A migration function for a [saved object type](./kibana-plugin-server.savedobjectstype.md) used to migrate it to a given version | | [SavedObjectSanitizedDoc](./kibana-plugin-server.savedobjectsanitizeddoc.md) | | | [SavedObjectsClientContract](./kibana-plugin-server.savedobjectsclientcontract.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing plugin state.\#\# SavedObjectsClient errorsSince the SavedObjectsClient has its hands in everything we are a little paranoid about the way we present errors back to to application code. Ideally, all errors will be either:1. Caused by bad implementation (ie. undefined is not a function) and as such unpredictable 2. An error that has been classified and decorated appropriately by the decorators in [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md)Type 1 errors are inevitable, but since all expected/handle-able errors should be Type 2 the isXYZError() helpers exposed at SavedObjectsErrorHelpers should be used to understand and manage error responses from the SavedObjectsClient.Type 2 errors are decorated versions of the source error, so if the elasticsearch client threw an error it will be decorated based on its type. That means that rather than looking for error.body.error.type or doing substring checks on error.body.error.reason, just use the helpers to understand the meaning of the error:\`\`\`js if (SavedObjectsErrorHelpers.isNotFoundError(error)) { // handle 404 }if (SavedObjectsErrorHelpers.isNotAuthorizedError(error)) { // 401 handling should be automatic, but in case you wanted to know }// always rethrow the error unless you handle it throw error; \`\`\`\#\#\# 404s from missing indexFrom the perspective of application code and APIs the SavedObjectsClient is a black box that persists objects. One of the internal details that users have no control over is that we use an elasticsearch index for persistance and that index might be missing.At the time of writing we are in the process of transitioning away from the operating assumption that the SavedObjects index is always available. Part of this transition is handling errors resulting from an index missing. These used to trigger a 500 error in most cases, and in others cause 404s with different error messages.From my (Spencer) perspective, a 404 from the SavedObjectsApi is a 404; The object the request/call was targeting could not be found. This is why \#14141 takes special care to ensure that 404 errors are generic and don't distinguish between index missing or document missing.\#\#\# 503s from missing indexUnlike all other methods, create requests are supposed to succeed even when the Kibana index does not exist because it will be automatically created by elasticsearch. When that is not the case it is because Elasticsearch's action.auto_create_index setting prevents it from being created automatically so we throw a special 503 with the intention of informing the user that their Elasticsearch settings need to be updated.See [SavedObjectsClient](./kibana-plugin-server.savedobjectsclient.md) See [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md) | | [SavedObjectsClientFactory](./kibana-plugin-server.savedobjectsclientfactory.md) | Describes the factory used to create instances of the Saved Objects Client. | diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectmigrationcontext.log.md b/docs/development/core/server/kibana-plugin-server.savedobjectmigrationcontext.log.md new file mode 100644 index 0000000000000..4e4eaa3ca91e6 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectmigrationcontext.log.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectMigrationContext](./kibana-plugin-server.savedobjectmigrationcontext.md) > [log](./kibana-plugin-server.savedobjectmigrationcontext.log.md) + +## SavedObjectMigrationContext.log property + +logger instance to be used by the migration handler + +Signature: + +```typescript +log: SavedObjectsMigrationLogger; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectmigrationcontext.md b/docs/development/core/server/kibana-plugin-server.savedobjectmigrationcontext.md new file mode 100644 index 0000000000000..77698b37cd3c9 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectmigrationcontext.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectMigrationContext](./kibana-plugin-server.savedobjectmigrationcontext.md) + +## SavedObjectMigrationContext interface + +Migration context provided when invoking a [migration handler](./kibana-plugin-server.savedobjectmigrationfn.md) + +Signature: + +```typescript +export interface SavedObjectMigrationContext +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [log](./kibana-plugin-server.savedobjectmigrationcontext.log.md) | SavedObjectsMigrationLogger | logger instance to be used by the migration handler | + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectmigrationfn.md b/docs/development/core/server/kibana-plugin-server.savedobjectmigrationfn.md index 629d748083737..838fa55a7f089 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectmigrationfn.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectmigrationfn.md @@ -4,10 +4,27 @@ ## SavedObjectMigrationFn type -A migration function defined for a [saved objects type](./kibana-plugin-server.savedobjectstype.md) used to migrate it's +A migration function for a [saved object type](./kibana-plugin-server.savedobjectstype.md) used to migrate it to a given version Signature: ```typescript -export declare type SavedObjectMigrationFn = (doc: SavedObjectUnsanitizedDoc, log: SavedObjectsMigrationLogger) => SavedObjectUnsanitizedDoc; +export declare type SavedObjectMigrationFn = (doc: SavedObjectUnsanitizedDoc, context: SavedObjectMigrationContext) => SavedObjectUnsanitizedDoc; ``` + +## Example + + +```typescript +const migrateProperty: SavedObjectMigrationFn = (doc, { log }) => { + if(doc.attributes.someProp === null) { + log.warn('Skipping migration'); + } else { + doc.attributes.someProp = migrateProperty(doc.attributes.someProp); + } + + return doc; +} + +``` + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.md index dfff863898a2b..67746126e79b4 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.md @@ -18,4 +18,5 @@ export interface SavedObjectsClientWrapperOptions | --- | --- | --- | | [client](./kibana-plugin-server.savedobjectsclientwrapperoptions.client.md) | SavedObjectsClientContract | | | [request](./kibana-plugin-server.savedobjectsclientwrapperoptions.request.md) | KibanaRequest | | +| [typeRegistry](./kibana-plugin-server.savedobjectsclientwrapperoptions.typeregistry.md) | ISavedObjectTypeRegistry | | diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.typeregistry.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.typeregistry.md new file mode 100644 index 0000000000000..afd6898699384 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.typeregistry.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsClientWrapperOptions](./kibana-plugin-server.savedobjectsclientwrapperoptions.md) > [typeRegistry](./kibana-plugin-server.savedobjectsclientwrapperoptions.typeregistry.md) + +## SavedObjectsClientWrapperOptions.typeRegistry property + +Signature: + +```typescript +typeRegistry: ISavedObjectTypeRegistry; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.md b/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.md index 9981bfee0cb7d..b6f2e7320c48a 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.md @@ -4,7 +4,7 @@ ## SavedObjectsServiceSetup interface -Saved Objects is Kibana's data persistence mechanism allowing plugins to use Elasticsearch for storing and querying state. The SavedObjectsServiceSetup API exposes methods for creating and registering Saved Object client wrappers. +Saved Objects is Kibana's data persistence mechanism allowing plugins to use Elasticsearch for storing and querying state. The SavedObjectsServiceSetup API exposes methods for registering Saved Object types, creating and registering Saved Object client wrappers and factories. Signature: @@ -14,11 +14,9 @@ export interface SavedObjectsServiceSetup ## Remarks -Note: The Saved Object setup API's should only be used for creating and registering client wrappers. Constructing a Saved Objects client or repository for use within your own plugin won't have any of the registered wrappers applied and is considered an anti-pattern. Use the Saved Objects client from the [SavedObjectsServiceStart\#getScopedClient](./kibana-plugin-server.savedobjectsservicestart.md) method or the [route handler context](./kibana-plugin-server.requesthandlercontext.md) instead. +When plugins access the Saved Objects client, a new client is created using the factory provided to `setClientFactory` and wrapped by all wrappers registered through `addClientWrapper`. -When plugins access the Saved Objects client, a new client is created using the factory provided to `setClientFactory` and wrapped by all wrappers registered through `addClientWrapper`. To create a factory or wrapper, plugins will have to construct a Saved Objects client. First create a repository by calling `scopedRepository` or `internalRepository` and then use this repository as the argument to the [SavedObjectsClient](./kibana-plugin-server.savedobjectsclient.md) constructor. - -## Example +## Example 1 ```ts @@ -34,10 +32,26 @@ export class Plugin() { ``` +## Example 2 + + +```ts +import { SavedObjectsClient, CoreSetup } from 'src/core/server'; +import { mySoType } from './saved_objects' + +export class Plugin() { + setup: (core: CoreSetup) => { + core.savedObjects.registerType(mySoType); + } +} + +``` + ## Properties | Property | Type | Description | | --- | --- | --- | | [addClientWrapper](./kibana-plugin-server.savedobjectsservicesetup.addclientwrapper.md) | (priority: number, id: string, factory: SavedObjectsClientWrapperFactory) => void | Add a [client wrapper factory](./kibana-plugin-server.savedobjectsclientwrapperfactory.md) with the given priority. | +| [registerType](./kibana-plugin-server.savedobjectsservicesetup.registertype.md) | (type: SavedObjectsType) => void | Register a [savedObjects type](./kibana-plugin-server.savedobjectstype.md) definition.See the [mappings format](./kibana-plugin-server.savedobjectstypemappingdefinition.md) and [migration format](./kibana-plugin-server.savedobjectmigrationmap.md) for more details about these. | | [setClientFactoryProvider](./kibana-plugin-server.savedobjectsservicesetup.setclientfactoryprovider.md) | (clientFactoryProvider: SavedObjectsClientFactoryProvider) => void | Set the default [factory provider](./kibana-plugin-server.savedobjectsclientfactoryprovider.md) for creating Saved Objects clients. Only one provider can be set, subsequent calls to this method will fail. | diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.registertype.md b/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.registertype.md new file mode 100644 index 0000000000000..89102d292d634 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.registertype.md @@ -0,0 +1,60 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsServiceSetup](./kibana-plugin-server.savedobjectsservicesetup.md) > [registerType](./kibana-plugin-server.savedobjectsservicesetup.registertype.md) + +## SavedObjectsServiceSetup.registerType property + +Register a [savedObjects type](./kibana-plugin-server.savedobjectstype.md) definition. + +See the [mappings format](./kibana-plugin-server.savedobjectstypemappingdefinition.md) and [migration format](./kibana-plugin-server.savedobjectmigrationmap.md) for more details about these. + +Signature: + +```typescript +registerType: (type: SavedObjectsType) => void; +``` + +## Remarks + +The type definition is an aggregation of the legacy savedObjects `schema`, `mappings` and `migration` concepts. This API is the single entry point to register saved object types in the new platform. + +## Example + + +```ts +// src/plugins/my_plugin/server/saved_objects/my_type.ts +import { SavedObjectsType } from 'src/core/server'; +import * as migrations from './migrations'; + +export const myType: SavedObjectsType = { + name: 'MyType', + hidden: false, + namespaceAgnostic: true, + mappings: { + properties: { + textField: { + type: 'text', + }, + boolField: { + type: 'boolean', + }, + }, + }, + migrations: { + '2.0.0': migrations.migrateToV2, + '2.1.0': migrations.migrateToV2_1 + }, +}; + +// src/plugins/my_plugin/server/plugin.ts +import { SavedObjectsClient, CoreSetup } from 'src/core/server'; +import { myType } from './saved_objects'; + +export class Plugin() { + setup: (core: CoreSetup) => { + core.savedObjects.registerType(myType); + } +} + +``` + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.gettyperegistry.md b/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.gettyperegistry.md new file mode 100644 index 0000000000000..82e67bb307588 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.gettyperegistry.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsServiceStart](./kibana-plugin-server.savedobjectsservicestart.md) > [getTypeRegistry](./kibana-plugin-server.savedobjectsservicestart.gettyperegistry.md) + +## SavedObjectsServiceStart.getTypeRegistry property + +Returns the [registry](./kibana-plugin-server.isavedobjecttyperegistry.md) containing all registered [saved object types](./kibana-plugin-server.savedobjectstype.md) + +Signature: + +```typescript +getTypeRegistry: () => ISavedObjectTypeRegistry; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.md b/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.md index ad34d76bb33f4..293255bb33c2a 100644 --- a/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.md +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.md @@ -20,4 +20,5 @@ export interface SavedObjectsServiceStart | [createScopedRepository](./kibana-plugin-server.savedobjectsservicestart.createscopedrepository.md) | (req: KibanaRequest, extraTypes?: string[]) => ISavedObjectsRepository | Creates a [Saved Objects repository](./kibana-plugin-server.isavedobjectsrepository.md) that uses the credentials from the passed in request to authenticate with Elasticsearch. | | [createSerializer](./kibana-plugin-server.savedobjectsservicestart.createserializer.md) | () => SavedObjectsSerializer | Creates a [serializer](./kibana-plugin-server.savedobjectsserializer.md) that is aware of all registered types. | | [getScopedClient](./kibana-plugin-server.savedobjectsservicestart.getscopedclient.md) | (req: KibanaRequest, options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract | Creates a [Saved Objects client](./kibana-plugin-server.savedobjectsclientcontract.md) that uses the credentials from the passed in request to authenticate with Elasticsearch. If other plugins have registered Saved Objects client wrappers, these will be applied to extend the functionality of the client.A client that is already scoped to the incoming request is also exposed from the route handler context see [RequestHandlerContext](./kibana-plugin-server.requesthandlercontext.md). | +| [getTypeRegistry](./kibana-plugin-server.savedobjectsservicestart.gettyperegistry.md) | () => ISavedObjectTypeRegistry | Returns the [registry](./kibana-plugin-server.isavedobjecttyperegistry.md) containing all registered [saved object types](./kibana-plugin-server.savedobjectstype.md) | diff --git a/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.getalltypes.md b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.getalltypes.md new file mode 100644 index 0000000000000..d71b392c40840 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.getalltypes.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectTypeRegistry](./kibana-plugin-server.savedobjecttyperegistry.md) > [getAllTypes](./kibana-plugin-server.savedobjecttyperegistry.getalltypes.md) + +## SavedObjectTypeRegistry.getAllTypes() method + +Return all [types](./kibana-plugin-server.savedobjectstype.md) currently registered. + +Signature: + +```typescript +getAllTypes(): SavedObjectsType[]; +``` +Returns: + +`SavedObjectsType[]` + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.getindex.md b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.getindex.md new file mode 100644 index 0000000000000..3479600456c47 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.getindex.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectTypeRegistry](./kibana-plugin-server.savedobjecttyperegistry.md) > [getIndex](./kibana-plugin-server.savedobjecttyperegistry.getindex.md) + +## SavedObjectTypeRegistry.getIndex() method + +Returns the `indexPattern` property for given type, or `undefined` if the type is not registered. + +Signature: + +```typescript +getIndex(type: string): string | undefined; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| type | string | | + +Returns: + +`string | undefined` + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.gettype.md b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.gettype.md new file mode 100644 index 0000000000000..b32301a253731 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.gettype.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectTypeRegistry](./kibana-plugin-server.savedobjecttyperegistry.md) > [getType](./kibana-plugin-server.savedobjecttyperegistry.gettype.md) + +## SavedObjectTypeRegistry.getType() method + +Return the [type](./kibana-plugin-server.savedobjectstype.md) definition for given type name. + +Signature: + +```typescript +getType(type: string): SavedObjectsType | undefined; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| type | string | | + +Returns: + +`SavedObjectsType | undefined` + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.ishidden.md b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.ishidden.md new file mode 100644 index 0000000000000..956ba2cbc1dbd --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.ishidden.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectTypeRegistry](./kibana-plugin-server.savedobjecttyperegistry.md) > [isHidden](./kibana-plugin-server.savedobjecttyperegistry.ishidden.md) + +## SavedObjectTypeRegistry.isHidden() method + +Returns the `hidden` property for given type, or `false` if the type is not registered. + +Signature: + +```typescript +isHidden(type: string): boolean; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| type | string | | + +Returns: + +`boolean` + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.isnamespaceagnostic.md b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.isnamespaceagnostic.md new file mode 100644 index 0000000000000..e6e578d893648 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.isnamespaceagnostic.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectTypeRegistry](./kibana-plugin-server.savedobjecttyperegistry.md) > [isNamespaceAgnostic](./kibana-plugin-server.savedobjecttyperegistry.isnamespaceagnostic.md) + +## SavedObjectTypeRegistry.isNamespaceAgnostic() method + +Returns the `namespaceAgnostic` property for given type, or `false` if the type is not registered. + +Signature: + +```typescript +isNamespaceAgnostic(type: string): boolean; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| type | string | | + +Returns: + +`boolean` + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.md b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.md new file mode 100644 index 0000000000000..3daad35808624 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectTypeRegistry](./kibana-plugin-server.savedobjecttyperegistry.md) + +## SavedObjectTypeRegistry class + +Registry holding information about all the registered [saved object types](./kibana-plugin-server.savedobjectstype.md). + +Signature: + +```typescript +export declare class SavedObjectTypeRegistry +``` + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [getAllTypes()](./kibana-plugin-server.savedobjecttyperegistry.getalltypes.md) | | Return all [types](./kibana-plugin-server.savedobjectstype.md) currently registered. | +| [getIndex(type)](./kibana-plugin-server.savedobjecttyperegistry.getindex.md) | | Returns the indexPattern property for given type, or undefined if the type is not registered. | +| [getType(type)](./kibana-plugin-server.savedobjecttyperegistry.gettype.md) | | Return the [type](./kibana-plugin-server.savedobjectstype.md) definition for given type name. | +| [isHidden(type)](./kibana-plugin-server.savedobjecttyperegistry.ishidden.md) | | Returns the hidden property for given type, or false if the type is not registered. | +| [isNamespaceAgnostic(type)](./kibana-plugin-server.savedobjecttyperegistry.isnamespaceagnostic.md) | | Returns the namespaceAgnostic property for given type, or false if the type is not registered. | +| [registerType(type)](./kibana-plugin-server.savedobjecttyperegistry.registertype.md) | | Register a [type](./kibana-plugin-server.savedobjectstype.md) inside the registry. A type can only be registered once. subsequent calls with the same type name will throw an error. | + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.registertype.md b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.registertype.md new file mode 100644 index 0000000000000..4e6d62ccd28d0 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjecttyperegistry.registertype.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectTypeRegistry](./kibana-plugin-server.savedobjecttyperegistry.md) > [registerType](./kibana-plugin-server.savedobjecttyperegistry.registertype.md) + +## SavedObjectTypeRegistry.registerType() method + +Register a [type](./kibana-plugin-server.savedobjectstype.md) inside the registry. A type can only be registered once. subsequent calls with the same type name will throw an error. + +Signature: + +```typescript +registerType(type: SavedObjectsType): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| type | SavedObjectsType | | + +Returns: + +`void` + diff --git a/src/core/CONVENTIONS.md b/src/core/CONVENTIONS.md index dd83ab2daca82..2769079757bc3 100644 --- a/src/core/CONVENTIONS.md +++ b/src/core/CONVENTIONS.md @@ -7,6 +7,7 @@ - [Applications](#applications) - [Services](#services) - [Usage Collection](#usage-collection) + - [Saved Objects Types](#saved-objects-types) ## Plugin Structure @@ -31,6 +32,9 @@ my_plugin/ │ └── index.ts ├── collectors │ └── register.ts + ├── saved_objects + │ ├── index.ts + │ └── my_type.ts    ├── services    │   ├── my_service    │   │ └── index.ts @@ -259,6 +263,45 @@ export function registerMyPluginUsageCollector(usageCollection?: UsageCollection } ``` +### Saved Objects Types + +Saved object type definitions should be defined in their own `server/saved_objects` directory. + +The folder should contain a file per type, named after the snake_case name of the type, and an `index.ts` file exporting all the types. + +```typescript +// src/plugins/my-plugin/server/saved_objects/my_type.ts +import { SavedObjectsType } from 'src/core/server'; + +export const myType: SavedObjectsType = { + name: 'my-type', + hidden: false, + namespaceAgnostic: true, + mappings: { + properties: { + someField: { + type: 'text', + }, + anotherField: { + type: 'text', + }, + }, + }, + migrations: { + '1.0.0': migrateFirstTypeToV1, + '2.0.0': migrateFirstTypeToV2, + }, +}; +``` + +```typescript +// src/plugins/my-plugin/server/saved_objects/index.ts + +export { myType } from './my_type'; +``` + +Migration example from the legacy format is available in `src/core/MIGRATION_EXAMPLES.md#saved-objects-types` + ### Naming conventions Export start and setup contracts as `MyPluginStart` and `MyPluginSetup`. diff --git a/src/core/MIGRATION.md b/src/core/MIGRATION.md index d33fd9bcce7a0..6ee432635a947 100644 --- a/src/core/MIGRATION.md +++ b/src/core/MIGRATION.md @@ -1207,6 +1207,9 @@ In server code, `core` can be accessed from either `server.newPlatform` or `kbnS | `request.getSavedObjectsClient` | [`context.core.savedObjects.client`](/docs/development/core/server/kibana-plugin-server.requesthandlercontext.core.md) | | | `request.getUiSettingsService` | [`context.uiSettings.client`](/docs/development/core/server/kibana-plugin-server.iuisettingsclient.md) | | | `kibana.Plugin.deprecations` | [Handle plugin configuration deprecations](#handle-plugin-config-deprecations) and [`PluginConfigDescriptor.deprecations`](docs/development/core/server/kibana-plugin-server.pluginconfigdescriptor.md) | Deprecations from New Platform are not applied to legacy configuration | +| `kibana.Plugin.savedObjectSchemas` | [`core.savedObjects.registerType`](docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.registertype.md) | [Examples](./MIGRATION_EXAMPLES.md#saved-objects-types) | +| `kibana.Plugin.mappings` | [`core.savedObjects.registerType`](docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.registertype.md) | [Examples](./MIGRATION_EXAMPLES.md#saved-objects-types) | +| `kibana.Plugin.migrations` | [`core.savedObjects.registerType`](docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.registertype.md) | [Examples](./MIGRATION_EXAMPLES.md#saved-objects-types) | _See also: [Server's CoreSetup API Docs](/docs/development/core/server/kibana-plugin-server.coresetup.md)_ diff --git a/src/core/MIGRATION_EXAMPLES.md b/src/core/MIGRATION_EXAMPLES.md index 5517dfa7f9a23..def83ba177fc9 100644 --- a/src/core/MIGRATION_EXAMPLES.md +++ b/src/core/MIGRATION_EXAMPLES.md @@ -19,6 +19,7 @@ APIs to their New Platform equivalents. - [Updating an application navlink](#updating-application-navlink) - [Chromeless Applications](#chromeless-applications) - [Render HTML Content](#render-html-content) + - [Saved Objects types](#saved-objects-types) ## Configuration @@ -737,3 +738,183 @@ router.get( } ); ``` + +## Saved Objects types + +In the legacy platform, saved object types were registered using static definitions in the `uiExports` part of +the plugin manifest. + +In the new platform, all these registration are to be performed programmatically during your plugin's `setup` phase, +using the core `savedObjects`'s `registerType` setup API. + +The most notable difference is that in the new platform, the type registration is performed in a single call to +`registerType`, passing a new `SavedObjectsType` structure that is a superset of the legacy `schema`, `migrations` +and `mappings`. + +### Concrete example + +Let say we have the following in a legacy plugin: + +```js +// src/legacy/core_plugins/my_plugin/index.js +import mappings from './mappings.json'; +import { migrations } from './migrations'; + +new kibana.Plugin({ + init(server){ + // [...] + }, + uiExports: { + mappings, + migrations, + savedObjectSchemas: { + 'first-type': { + isNamespaceAgnostic: true, + }, + 'second-type': { + isHidden: true, + }, + }, + }, +}) +``` + +```json +// src/legacy/core_plugins/my_plugin/mappings.json +{ + "first-type": { + "properties": { + "someField": { + "type": "text" + }, + "anotherField": { + "type": "text" + } + } + }, + "second-type": { + "properties": { + "textField": { + "type": "text" + }, + "boolField": { + "type": "boolean" + } + } + } +} +``` + +```js +// src/legacy/core_plugins/my_plugin/migrations.js +export const migrations = { + 'first-type': { + '1.0.0': migrateFirstTypeToV1, + '2.0.0': migrateFirstTypeToV2, + }, + 'second-type': { + '1.5.0': migrateSecondTypeToV15, + } +} +``` + +To migrate this, we will have to regroup the declaration per-type. That would become: + +First type: + +```typescript +// src/plugins/my_plugin/server/saved_objects/first_type.ts +import { SavedObjectsType } from 'src/core/server'; + +export const firstType: SavedObjectsType = { + name: 'first-type', + hidden: false, + namespaceAgnostic: true, + mappings: { + properties: { + someField: { + type: 'text', + }, + anotherField: { + type: 'text', + }, + }, + }, + migrations: { + '1.0.0': migrateFirstTypeToV1, + '2.0.0': migrateFirstTypeToV2, + }, +}; +``` + +Second type: + +```typescript +// src/plugins/my_plugin/server/saved_objects/second_type.ts +import { SavedObjectsType } from 'src/core/server'; + +export const secondType: SavedObjectsType = { + name: 'second-type', + hidden: true, + namespaceAgnostic: false, + mappings: { + properties: { + textField: { + type: 'text', + }, + boolField: { + type: 'boolean', + }, + }, + }, + migrations: { + '1.5.0': migrateSecondTypeToV15, + }, +}; +``` + +Registration in the plugin's setup phase: + +```typescript +// src/plugins/my_plugin/server/plugin.ts +import { firstType, secondType } from './saved_objects'; + +export class MyPlugin implements Plugin { + setup({ savedObjects }) { + savedObjects.registerType(firstType); + savedObjects.registerType(secondType); + } +} +``` + +### Changes in structure compared to legacy + +The NP `registerType` expected input is very close to the legacy format. However, there are some minor changes: + +- The `schema.isNamespaceAgnostic` property has been renamed: `SavedObjectsType.namespaceAgnostic` + +- The `schema.indexPattern` was accepting either a `string` or a `(config: LegacyConfig) => string`. `SavedObjectsType.indexPattern` only accepts a string, as you can access the configuration during your plugin's setup phase. + +- The migration function signature has changed: +In legacy, it was `(doc: SavedObjectUnsanitizedDoc, log: SavedObjectsMigrationLogger) => SavedObjectUnsanitizedDoc;` +In new platform, it is now `(doc: SavedObjectUnsanitizedDoc, context: SavedObjectMigrationContext) => SavedObjectUnsanitizedDoc;` + +With context being: + +```typescript +export interface SavedObjectMigrationContext { + log: SavedObjectsMigrationLogger; +} +``` + +The changes is very minor though. The legacy migration: + +```js +const migration = (doc, log) => {...} +``` + +Would be converted to: + +```typescript +const migration: SavedObjectMigrationFn = (doc, { log }) => {...} +``` \ No newline at end of file diff --git a/src/core/server/index.ts b/src/core/server/index.ts index 52827b72ee0cc..e45d4f28edcc3 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -201,6 +201,7 @@ export { SavedObjectsImportRetry, SavedObjectsImportUnknownError, SavedObjectsImportUnsupportedTypeError, + SavedObjectMigrationContext, SavedObjectsMigrationLogger, SavedObjectsRawDoc, SavedObjectSanitizedDoc, @@ -224,6 +225,7 @@ export { SavedObjectsTypeMappingDefinition, SavedObjectsMappingProperties, SavedObjectTypeRegistry, + ISavedObjectTypeRegistry, SavedObjectsType, SavedObjectMigrationMap, SavedObjectMigrationFn, diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts index b2501496d87ef..44f77b5ad215e 100644 --- a/src/core/server/legacy/legacy_service.ts +++ b/src/core/server/legacy/legacy_service.ts @@ -263,6 +263,7 @@ export class LegacyService implements CoreService { createScopedRepository: startDeps.core.savedObjects.createScopedRepository, createInternalRepository: startDeps.core.savedObjects.createInternalRepository, createSerializer: startDeps.core.savedObjects.createSerializer, + getTypeRegistry: startDeps.core.savedObjects.getTypeRegistry, }, uiSettings: { asScopedToClient: startDeps.core.uiSettings.asScopedToClient }, }; @@ -298,6 +299,7 @@ export class LegacyService implements CoreService { savedObjects: { setClientFactoryProvider: setupDeps.core.savedObjects.setClientFactoryProvider, addClientWrapper: setupDeps.core.savedObjects.addClientWrapper, + registerType: setupDeps.core.savedObjects.registerType, }, uiSettings: { register: setupDeps.core.uiSettings.register, @@ -329,7 +331,6 @@ export class LegacyService implements CoreService { __internals: { hapiServer: setupDeps.core.http.server, kibanaMigrator: startDeps.core.savedObjects.migrator, - typeRegistry: startDeps.core.savedObjects.typeRegistry, uiPlugins: setupDeps.core.plugins.uiPlugins, elasticsearch: setupDeps.core.elasticsearch, rendering: setupDeps.core.rendering, diff --git a/src/core/server/mocks.ts b/src/core/server/mocks.ts index d6554babab53e..b8380a3045962 100644 --- a/src/core/server/mocks.ts +++ b/src/core/server/mocks.ts @@ -114,18 +114,12 @@ function createCoreSetupMock() { register: uiSettingsServiceMock.createSetupContract().register, }; - const savedObjectsService = savedObjectsServiceMock.createSetupContract(); - const savedObjectMock: jest.Mocked = { - addClientWrapper: savedObjectsService.addClientWrapper, - setClientFactoryProvider: savedObjectsService.setClientFactoryProvider, - }; - const mock: CoreSetupMockType = { capabilities: capabilitiesServiceMock.createSetupContract(), context: contextServiceMock.createSetupContract(), elasticsearch: elasticsearchServiceMock.createSetup(), http: httpMock, - savedObjects: savedObjectMock, + savedObjects: savedObjectsServiceMock.createInternalSetupContract(), uiSettings: uiSettingsMock, uuid: uuidServiceMock.createSetupContract(), getStartServices: jest diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts index a7b555a9eba01..a8a16713f69a4 100644 --- a/src/core/server/plugins/plugin_context.ts +++ b/src/core/server/plugins/plugin_context.ts @@ -169,6 +169,7 @@ export function createPluginSetupContext( savedObjects: { setClientFactoryProvider: deps.savedObjects.setClientFactoryProvider, addClientWrapper: deps.savedObjects.addClientWrapper, + registerType: deps.savedObjects.registerType, }, uiSettings: { register: deps.uiSettings.register, @@ -206,6 +207,7 @@ export function createPluginStartContext( createInternalRepository: deps.savedObjects.createInternalRepository, createScopedRepository: deps.savedObjects.createScopedRepository, createSerializer: deps.savedObjects.createSerializer, + getTypeRegistry: deps.savedObjects.getTypeRegistry, }, uiSettings: { asScopedToClient: deps.uiSettings.asScopedToClient, diff --git a/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap b/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap index 7846e7f1a802a..89ff2b542c60f 100644 --- a/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap +++ b/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap @@ -64,8 +64,8 @@ Array [ }, }, "migrations": Object { - "1.0.0": [MockFunction], - "2.0.4": [MockFunction], + "1.0.0": [Function], + "2.0.4": [Function], }, "name": "typeA", "namespaceAgnostic": true, @@ -100,7 +100,7 @@ Array [ }, }, "migrations": Object { - "1.5.3": [MockFunction], + "1.5.3": [Function], }, "name": "typeC", "namespaceAgnostic": false, diff --git a/src/core/server/saved_objects/index.ts b/src/core/server/saved_objects/index.ts index 5be4458bdf2af..9bfe658028258 100644 --- a/src/core/server/saved_objects/index.ts +++ b/src/core/server/saved_objects/index.ts @@ -64,7 +64,11 @@ export { SavedObjectsTypeMappingDefinitions, } from './mappings'; -export { SavedObjectMigrationMap, SavedObjectMigrationFn } from './migrations'; +export { + SavedObjectMigrationMap, + SavedObjectMigrationFn, + SavedObjectMigrationContext, +} from './migrations'; export { SavedObjectsType } from './types'; diff --git a/src/core/server/saved_objects/migrations/core/document_migrator.test.ts b/src/core/server/saved_objects/migrations/core/document_migrator.test.ts index 0e3a4780e12b6..ef3f546b5e574 100644 --- a/src/core/server/saved_objects/migrations/core/document_migrator.test.ts +++ b/src/core/server/saved_objects/migrations/core/document_migrator.test.ts @@ -585,7 +585,7 @@ describe('DocumentMigrator', () => { typeRegistry: createRegistry({ name: 'dog', migrations: { - '1.2.3': (doc, log) => { + '1.2.3': (doc, { log }) => { log.info(logTestMsg); log.warning(logTestMsg); return doc; diff --git a/src/core/server/saved_objects/migrations/core/document_migrator.ts b/src/core/server/saved_objects/migrations/core/document_migrator.ts index b5019b2874bec..0284f513a361c 100644 --- a/src/core/server/saved_objects/migrations/core/document_migrator.ts +++ b/src/core/server/saved_objects/migrations/core/document_migrator.ts @@ -309,7 +309,8 @@ function wrapWithTry( ) { return function tryTransformDoc(doc: SavedObjectUnsanitizedDoc) { try { - const result = migrationFn(doc, new MigrationLogger(log)); + const context = { log: new MigrationLogger(log) }; + const result = migrationFn(doc, context); // A basic sanity check to help migration authors detect basic errors // (e.g. forgetting to return the transformed doc) diff --git a/src/core/server/saved_objects/migrations/index.ts b/src/core/server/saved_objects/migrations/index.ts index e96986bd702e6..dc966f0797822 100644 --- a/src/core/server/saved_objects/migrations/index.ts +++ b/src/core/server/saved_objects/migrations/index.ts @@ -18,4 +18,8 @@ */ export { KibanaMigrator, IKibanaMigrator } from './kibana'; -export { SavedObjectMigrationFn, SavedObjectMigrationMap } from './types'; +export { + SavedObjectMigrationFn, + SavedObjectMigrationMap, + SavedObjectMigrationContext, +} from './types'; diff --git a/src/core/server/saved_objects/migrations/types.ts b/src/core/server/saved_objects/migrations/types.ts index 01741dd2ded1a..6bc085dde872e 100644 --- a/src/core/server/saved_objects/migrations/types.ts +++ b/src/core/server/saved_objects/migrations/types.ts @@ -21,14 +21,41 @@ import { SavedObjectUnsanitizedDoc } from '../serialization'; import { SavedObjectsMigrationLogger } from './core/migration_logger'; /** - * A migration function defined for a {@link SavedObjectsType | saved objects type} - * used to migrate it's {@link SavedObjectUnsanitizedDoc | documents} + * A migration function for a {@link SavedObjectsType | saved object type} + * used to migrate it to a given version + * + * @example + * ```typescript + * const migrateProperty: SavedObjectMigrationFn = (doc, { log }) => { + * if(doc.attributes.someProp === null) { + * log.warn('Skipping migration'); + * } else { + * doc.attributes.someProp = migrateProperty(doc.attributes.someProp); + * } + * + * return doc; + * } + * ``` + * + * @public */ export type SavedObjectMigrationFn = ( doc: SavedObjectUnsanitizedDoc, - log: SavedObjectsMigrationLogger + context: SavedObjectMigrationContext ) => SavedObjectUnsanitizedDoc; +/** + * Migration context provided when invoking a {@link SavedObjectMigrationFn | migration handler} + * + * @public + */ +export interface SavedObjectMigrationContext { + /** + * logger instance to be used by the migration handler + */ + log: SavedObjectsMigrationLogger; +} + /** * A map of {@link SavedObjectMigrationFn | migration functions} to be used for a given type. * The map's keys must be valid semver versions. diff --git a/src/core/server/saved_objects/saved_objects_service.mock.ts b/src/core/server/saved_objects/saved_objects_service.mock.ts index 70f3d5a5b18e4..cbdff16324536 100644 --- a/src/core/server/saved_objects/saved_objects_service.mock.ts +++ b/src/core/server/saved_objects/saved_objects_service.mock.ts @@ -38,11 +38,13 @@ const createStartContractMock = () => { createInternalRepository: jest.fn(), createScopedRepository: jest.fn(), createSerializer: jest.fn(), + getTypeRegistry: jest.fn(), }; startContrat.getScopedClient.mockReturnValue(savedObjectsClientMock.create()); startContrat.createInternalRepository.mockReturnValue(savedObjectsRepositoryMock.create()); startContrat.createScopedRepository.mockReturnValue(savedObjectsRepositoryMock.create()); + startContrat.getTypeRegistry.mockReturnValue(typeRegistryMock.create()); return startContrat; }; @@ -52,7 +54,6 @@ const createInternalStartContractMock = () => { ...createStartContractMock(), clientProvider: savedObjectsClientProviderMock.create(), migrator: mockKibanaMigrator.create(), - typeRegistry: typeRegistryMock.create(), }; return internalStartContract; @@ -62,6 +63,7 @@ const createSetupContractMock = () => { const setupContract: jest.Mocked = { setClientFactoryProvider: jest.fn(), addClientWrapper: jest.fn(), + registerType: jest.fn(), }; return setupContract; @@ -70,7 +72,6 @@ const createSetupContractMock = () => { const createInternalSetupContractMock = () => { const internalSetupContract: jest.Mocked = { ...createSetupContractMock(), - registerType: jest.fn(), }; return internalSetupContract; }; diff --git a/src/core/server/saved_objects/saved_objects_service.test.ts b/src/core/server/saved_objects/saved_objects_service.test.ts index 0c7bedecf39f5..a1e2c1e8dbf26 100644 --- a/src/core/server/saved_objects/saved_objects_service.test.ts +++ b/src/core/server/saved_objects/saved_objects_service.test.ts @@ -130,7 +130,7 @@ describe('SavedObjectsService', () => { }); }); - describe('registerType', () => { + describe('#registerType', () => { it('registers the type to the internal typeRegistry', async () => { const coreContext = createCoreContext(); const soService = new SavedObjectsService(coreContext); @@ -231,5 +231,16 @@ describe('SavedObjectsService', () => { expect(startContract.migrator).toBe(migratorInstanceMock); expect(migratorInstanceMock.runMigrations).toHaveBeenCalledTimes(1); }); + + describe('#getTypeRegistry', () => { + it('returns the internal type registry of the service', async () => { + const coreContext = createCoreContext({ skipMigration: false }); + const soService = new SavedObjectsService(coreContext); + await soService.setup(createSetupDeps()); + const { getTypeRegistry } = await soService.start({}); + + expect(getTypeRegistry()).toBe(typeRegistryInstanceMock); + }); + }); }); }); diff --git a/src/core/server/saved_objects/saved_objects_service.ts b/src/core/server/saved_objects/saved_objects_service.ts index fa2b67a3e43b2..da8f7ab96d689 100644 --- a/src/core/server/saved_objects/saved_objects_service.ts +++ b/src/core/server/saved_objects/saved_objects_service.ts @@ -53,26 +53,13 @@ import { registerRoutes } from './routes'; /** * Saved Objects is Kibana's data persistence mechanism allowing plugins to - * use Elasticsearch for storing and querying state. The - * SavedObjectsServiceSetup API exposes methods for creating and registering - * Saved Object client wrappers. + * use Elasticsearch for storing and querying state. The SavedObjectsServiceSetup API exposes methods + * for registering Saved Object types, creating and registering Saved Object client wrappers and factories. * * @remarks - * Note: The Saved Object setup API's should only be used for creating and - * registering client wrappers. Constructing a Saved Objects client or - * repository for use within your own plugin won't have any of the registered - * wrappers applied and is considered an anti-pattern. Use the Saved Objects - * client from the - * {@link SavedObjectsServiceStart | SavedObjectsServiceStart#getScopedClient } - * method or the {@link RequestHandlerContext | route handler context} instead. - * * When plugins access the Saved Objects client, a new client is created using * the factory provided to `setClientFactory` and wrapped by all wrappers - * registered through `addClientWrapper`. To create a factory or wrapper, - * plugins will have to construct a Saved Objects client. First create a - * repository by calling `scopedRepository` or `internalRepository` and then - * use this repository as the argument to the {@link SavedObjectsClient} - * constructor. + * registered through `addClientWrapper`. * * @example * ```ts @@ -87,6 +74,18 @@ import { registerRoutes } from './routes'; * } * ``` * + * @example + * ```ts + * import { SavedObjectsClient, CoreSetup } from 'src/core/server'; + * import { mySoType } from './saved_objects' + * + * export class Plugin() { + * setup: (core: CoreSetup) => { + * core.savedObjects.registerType(mySoType); + * } + * } + * ``` + * * @public */ export interface SavedObjectsServiceSetup { @@ -104,14 +103,60 @@ export interface SavedObjectsServiceSetup { id: string, factory: SavedObjectsClientWrapperFactory ) => void; + + /** + * Register a {@link SavedObjectsType | savedObjects type} definition. + * + * See the {@link SavedObjectsTypeMappingDefinition | mappings format} and + * {@link SavedObjectMigrationMap | migration format} for more details about these. + * + * @example + * ```ts + * // src/plugins/my_plugin/server/saved_objects/my_type.ts + * import { SavedObjectsType } from 'src/core/server'; + * import * as migrations from './migrations'; + * + * export const myType: SavedObjectsType = { + * name: 'MyType', + * hidden: false, + * namespaceAgnostic: true, + * mappings: { + * properties: { + * textField: { + * type: 'text', + * }, + * boolField: { + * type: 'boolean', + * }, + * }, + * }, + * migrations: { + * '2.0.0': migrations.migrateToV2, + * '2.1.0': migrations.migrateToV2_1 + * }, + * }; + * + * // src/plugins/my_plugin/server/plugin.ts + * import { SavedObjectsClient, CoreSetup } from 'src/core/server'; + * import { myType } from './saved_objects'; + * + * export class Plugin() { + * setup: (core: CoreSetup) => { + * core.savedObjects.registerType(myType); + * } + * } + * ``` + * + * @remarks The type definition is an aggregation of the legacy savedObjects `schema`, `mappings` and `migration` concepts. + * This API is the single entry point to register saved object types in the new platform. + */ + registerType: (type: SavedObjectsType) => void; } /** * @internal */ -export interface InternalSavedObjectsServiceSetup extends SavedObjectsServiceSetup { - registerType: (type: SavedObjectsType) => void; -} +export type InternalSavedObjectsServiceSetup = SavedObjectsServiceSetup; /** * Saved Objects is Kibana's data persisentence mechanism allowing plugins to @@ -159,6 +204,11 @@ export interface SavedObjectsServiceStart { * Creates a {@link SavedObjectsSerializer | serializer} that is aware of all registered types. */ createSerializer: () => SavedObjectsSerializer; + /** + * Returns the {@link ISavedObjectTypeRegistry | registry} containing all registered + * {@link SavedObjectsType | saved object types} + */ + getTypeRegistry: () => ISavedObjectTypeRegistry; } export interface InternalSavedObjectsServiceStart extends SavedObjectsServiceStart { @@ -170,10 +220,6 @@ export interface InternalSavedObjectsServiceStart extends SavedObjectsServiceSta * @deprecated Exposed only for injecting into Legacy */ clientProvider: ISavedObjectsClientProvider; - /** - * @deprecated Exposed only for injecting into Legacy - */ - typeRegistry: ISavedObjectTypeRegistry; } /** @@ -359,6 +405,7 @@ export class SavedObjectsService const repository = repositoryFactory.createScopedRepository(request); return new SavedObjectsClient(repository); }, + typeRegistry: this.typeRegistry, }); if (this.clientFactoryProvider) { const clientFactory = this.clientFactoryProvider(repositoryFactory); @@ -371,11 +418,11 @@ export class SavedObjectsService return { migrator, clientProvider, - typeRegistry: this.typeRegistry, getScopedClient: clientProvider.getClient.bind(clientProvider), createScopedRepository: repositoryFactory.createScopedRepository, createInternalRepository: repositoryFactory.createInternalRepository, createSerializer: () => new SavedObjectsSerializer(this.typeRegistry), + getTypeRegistry: () => this.typeRegistry, }; } diff --git a/src/core/server/saved_objects/saved_objects_type_registry.mock.ts b/src/core/server/saved_objects/saved_objects_type_registry.mock.ts index 6e11920db6b7d..435e352335ecf 100644 --- a/src/core/server/saved_objects/saved_objects_type_registry.mock.ts +++ b/src/core/server/saved_objects/saved_objects_type_registry.mock.ts @@ -17,9 +17,10 @@ * under the License. */ -import { ISavedObjectTypeRegistry } from './saved_objects_type_registry'; +import { ISavedObjectTypeRegistry, SavedObjectTypeRegistry } from './saved_objects_type_registry'; -const createRegistryMock = (): jest.Mocked => { +const createRegistryMock = (): jest.Mocked> => { const mock = { registerType: jest.fn(), getType: jest.fn(), diff --git a/src/core/server/saved_objects/saved_objects_type_registry.ts b/src/core/server/saved_objects/saved_objects_type_registry.ts index 3f26d696831fd..b73c80ad9dff7 100644 --- a/src/core/server/saved_objects/saved_objects_type_registry.ts +++ b/src/core/server/saved_objects/saved_objects_type_registry.ts @@ -23,14 +23,17 @@ import { SavedObjectsType } from './types'; /** * See {@link SavedObjectTypeRegistry} for documentation. * - * @internal - * */ -export type ISavedObjectTypeRegistry = PublicMethodsOf; + * @public + */ +export type ISavedObjectTypeRegistry = Pick< + SavedObjectTypeRegistry, + 'getType' | 'getAllTypes' | 'getIndex' | 'isNamespaceAgnostic' | 'isHidden' +>; /** - * Registry holding information about all the registered {@link SavedObjectsType | savedObject types}. + * Registry holding information about all the registered {@link SavedObjectsType | saved object types}. * - * @internal + * @public */ export class SavedObjectTypeRegistry { private readonly types = new Map(); diff --git a/src/core/server/saved_objects/service/lib/scoped_client_provider.test.js b/src/core/server/saved_objects/service/lib/scoped_client_provider.test.js index eb210b6843de0..aa9448e61009d 100644 --- a/src/core/server/saved_objects/service/lib/scoped_client_provider.test.js +++ b/src/core/server/saved_objects/service/lib/scoped_client_provider.test.js @@ -18,6 +18,7 @@ */ import { SavedObjectsClientProvider } from './scoped_client_provider'; +import { typeRegistryMock } from '../../saved_objects_type_registry.mock'; test(`uses default client factory when one isn't set`, () => { const returnValue = Symbol(); @@ -26,6 +27,7 @@ test(`uses default client factory when one isn't set`, () => { const clientProvider = new SavedObjectsClientProvider({ defaultClientFactory: defaultClientFactoryMock, + typeRegistry: typeRegistryMock.create(), }); const result = clientProvider.getClient(request); @@ -44,6 +46,7 @@ test(`uses custom client factory when one is set`, () => { const clientProvider = new SavedObjectsClientProvider({ defaultClientFactory: defaultClientFactoryMock, + typeRegistry: typeRegistryMock.create(), }); clientProvider.setClientFactory(customClientFactoryMock); const result = clientProvider.getClient(request); @@ -68,6 +71,7 @@ test(`throws error when registering a wrapper with a duplicate id`, () => { const defaultClientFactoryMock = jest.fn(); const clientProvider = new SavedObjectsClientProvider({ defaultClientFactory: defaultClientFactoryMock, + typeRegistry: typeRegistryMock.create(), }); const firstClientWrapperFactoryMock = jest.fn(); const secondClientWrapperFactoryMock = jest.fn(); @@ -80,9 +84,11 @@ test(`throws error when registering a wrapper with a duplicate id`, () => { test(`invokes and uses wrappers in specified order`, () => { const defaultClient = Symbol(); + const typeRegistry = typeRegistryMock.create(); const defaultClientFactoryMock = jest.fn().mockReturnValue(defaultClient); const clientProvider = new SavedObjectsClientProvider({ defaultClientFactory: defaultClientFactoryMock, + typeRegistry, }); const firstWrappedClient = Symbol('first client'); const firstClientWrapperFactoryMock = jest.fn().mockReturnValue(firstWrappedClient); @@ -98,18 +104,22 @@ test(`invokes and uses wrappers in specified order`, () => { expect(firstClientWrapperFactoryMock).toHaveBeenCalledWith({ request, client: secondWrapperClient, + typeRegistry, }); expect(secondClientWrapperFactoryMock).toHaveBeenCalledWith({ request, client: defaultClient, + typeRegistry, }); }); test(`does not invoke or use excluded wrappers`, () => { const defaultClient = Symbol(); + const typeRegistry = typeRegistryMock.create(); const defaultClientFactoryMock = jest.fn().mockReturnValue(defaultClient); const clientProvider = new SavedObjectsClientProvider({ defaultClientFactory: defaultClientFactoryMock, + typeRegistry, }); const firstWrappedClient = Symbol('first client'); const firstClientWrapperFactoryMock = jest.fn().mockReturnValue(firstWrappedClient); @@ -128,6 +138,7 @@ test(`does not invoke or use excluded wrappers`, () => { expect(firstClientWrapperFactoryMock).toHaveBeenCalledWith({ request, client: defaultClient, + typeRegistry, }); expect(secondClientWrapperFactoryMock).not.toHaveBeenCalled(); }); @@ -137,6 +148,7 @@ test(`allows all wrappers to be excluded`, () => { const defaultClientFactoryMock = jest.fn().mockReturnValue(defaultClient); const clientProvider = new SavedObjectsClientProvider({ defaultClientFactory: defaultClientFactoryMock, + typeRegistry: typeRegistryMock.create(), }); const firstWrappedClient = Symbol('first client'); const firstClientWrapperFactoryMock = jest.fn().mockReturnValue(firstWrappedClient); diff --git a/src/core/server/saved_objects/service/lib/scoped_client_provider.ts b/src/core/server/saved_objects/service/lib/scoped_client_provider.ts index 8aadc4f57317c..24813cd8d9ab8 100644 --- a/src/core/server/saved_objects/service/lib/scoped_client_provider.ts +++ b/src/core/server/saved_objects/service/lib/scoped_client_provider.ts @@ -19,6 +19,7 @@ import { PriorityCollection } from './priority_collection'; import { SavedObjectsClientContract } from '../../types'; import { SavedObjectsRepositoryFactory } from '../../saved_objects_service'; +import { ISavedObjectTypeRegistry } from '../../saved_objects_type_registry'; import { KibanaRequest } from '../../../http'; /** @@ -27,6 +28,7 @@ import { KibanaRequest } from '../../../http'; */ export interface SavedObjectsClientWrapperOptions { client: SavedObjectsClientContract; + typeRegistry: ISavedObjectTypeRegistry; request: KibanaRequest; } @@ -84,9 +86,17 @@ export class SavedObjectsClientProvider { }>(); private _clientFactory: SavedObjectsClientFactory; private readonly _originalClientFactory: SavedObjectsClientFactory; - - constructor({ defaultClientFactory }: { defaultClientFactory: SavedObjectsClientFactory }) { + private readonly _typeRegistry: ISavedObjectTypeRegistry; + + constructor({ + defaultClientFactory, + typeRegistry, + }: { + defaultClientFactory: SavedObjectsClientFactory; + typeRegistry: ISavedObjectTypeRegistry; + }) { this._originalClientFactory = this._clientFactory = defaultClientFactory; + this._typeRegistry = typeRegistry; } addClientWrapperFactory( @@ -129,6 +139,7 @@ export class SavedObjectsClientProvider { return factory({ request, client: clientToWrap, + typeRegistry: this._typeRegistry, }); }, client); } diff --git a/src/core/server/saved_objects/types.ts b/src/core/server/saved_objects/types.ts index 9c204784b0aeb..495d896ad12cd 100644 --- a/src/core/server/saved_objects/types.ts +++ b/src/core/server/saved_objects/types.ts @@ -34,6 +34,8 @@ export { } from './import/types'; import { LegacyConfig } from '../legacy'; +import { SavedObjectUnsanitizedDoc } from './serialization'; +import { SavedObjectsMigrationLogger } from './migrations/core/migration_logger'; export { SavedObjectAttributes, SavedObjectAttribute, @@ -273,9 +275,26 @@ export interface SavedObjectsLegacyMapping { * @deprecated */ export interface SavedObjectsLegacyMigrationDefinitions { - [type: string]: SavedObjectMigrationMap; + [type: string]: SavedObjectLegacyMigrationMap; } +/** + * @internal + * @deprecated + */ +export interface SavedObjectLegacyMigrationMap { + [version: string]: SavedObjectLegacyMigrationFn; +} + +/** + * @internal + * @deprecated + */ +export type SavedObjectLegacyMigrationFn = ( + doc: SavedObjectUnsanitizedDoc, + log: SavedObjectsMigrationLogger +) => SavedObjectUnsanitizedDoc; + /** * @internal * @deprecated diff --git a/src/core/server/saved_objects/utils.test.ts b/src/core/server/saved_objects/utils.test.ts index 1e2b9f6a0f694..0a56535ac8509 100644 --- a/src/core/server/saved_objects/utils.test.ts +++ b/src/core/server/saved_objects/utils.test.ts @@ -20,7 +20,8 @@ import { legacyServiceMock } from '../legacy/legacy_service.mock'; import { convertLegacyTypes, convertTypesToLegacySchema } from './utils'; import { SavedObjectsLegacyUiExports, SavedObjectsType } from './types'; -import { LegacyConfig } from 'kibana/server'; +import { LegacyConfig, SavedObjectMigrationContext } from 'kibana/server'; +import { SavedObjectUnsanitizedDoc } from './serialization'; describe('convertLegacyTypes', () => { let legacyConfig: ReturnType; @@ -190,8 +191,48 @@ describe('convertLegacyTypes', () => { const converted = convertLegacyTypes(uiExports, legacyConfig); expect(converted.length).toEqual(2); - expect(converted[0].migrations).toEqual(migrationsA); - expect(converted[1].migrations).toEqual(migrationsB); + expect(Object.keys(converted[0]!.migrations!)).toEqual(Object.keys(migrationsA)); + expect(Object.keys(converted[1]!.migrations!)).toEqual(Object.keys(migrationsB)); + }); + + it('converts the migration to the new format', () => { + const legacyMigration = jest.fn(); + const migrationsA = { + '1.0.0': legacyMigration, + }; + + const uiExports: SavedObjectsLegacyUiExports = { + savedObjectMappings: [ + { + pluginId: 'pluginA', + properties: { + typeA: { + properties: { + fieldA: { type: 'text' }, + }, + }, + }, + }, + ], + savedObjectMigrations: { + typeA: migrationsA, + }, + savedObjectSchemas: {}, + savedObjectValidations: {}, + savedObjectsManagement: {}, + }; + + const converted = convertLegacyTypes(uiExports, legacyConfig); + expect(Object.keys(converted[0]!.migrations!)).toEqual(['1.0.0']); + + const migration = converted[0]!.migrations!['1.0.0']!; + + const doc = {} as SavedObjectUnsanitizedDoc; + const context = { log: {} } as SavedObjectMigrationContext; + migration(doc, context); + + expect(legacyMigration).toHaveBeenCalledTimes(1); + expect(legacyMigration).toHaveBeenCalledWith(doc, context.log); }); it('merges everything when all are present', () => { diff --git a/src/core/server/saved_objects/utils.ts b/src/core/server/saved_objects/utils.ts index 5c4d0ccb84b25..bb2c42c6a362c 100644 --- a/src/core/server/saved_objects/utils.ts +++ b/src/core/server/saved_objects/utils.ts @@ -18,7 +18,12 @@ */ import { LegacyConfig } from '../legacy'; -import { SavedObjectsType, SavedObjectsLegacyUiExports } from './types'; +import { SavedObjectMigrationMap } from './migrations'; +import { + SavedObjectsType, + SavedObjectsLegacyUiExports, + SavedObjectLegacyMigrationMap, +} from './types'; import { SavedObjectsSchemaDefinition } from './schema'; /** @@ -49,7 +54,7 @@ export const convertLegacyTypes = ( ? schema.indexPattern(legacyConfig) : schema?.indexPattern, convertToAliasScript: schema?.convertToAliasScript, - migrations: migrations ?? {}, + migrations: convertLegacyMigrations(migrations ?? {}), }; }), ]; @@ -74,3 +79,14 @@ export const convertTypesToLegacySchema = ( }; }, {} as SavedObjectsSchemaDefinition); }; + +const convertLegacyMigrations = ( + legacyMigrations: SavedObjectLegacyMigrationMap +): SavedObjectMigrationMap => { + return Object.entries(legacyMigrations).reduce((migrated, [version, migrationFn]) => { + return { + ...migrated, + [version]: (doc, context) => migrationFn(doc, context.log), + }; + }, {} as SavedObjectMigrationMap); +}; diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index f717f30fdb0cf..8f4feb7169651 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -929,6 +929,9 @@ export type IsAuthenticated = (request: KibanaRequest | LegacyRequest) => boolea // @public export type ISavedObjectsRepository = Pick; +// @public +export type ISavedObjectTypeRegistry = Pick; + // @public export type IScopedClusterClient = Pick; @@ -1489,12 +1492,15 @@ export interface SavedObjectAttributes { // @public export type SavedObjectAttributeSingle = string | number | boolean | null | undefined | SavedObjectAttributes; +// @public +export interface SavedObjectMigrationContext { + log: SavedObjectsMigrationLogger; +} + // Warning: (ae-forgotten-export) The symbol "SavedObjectUnsanitizedDoc" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "SavedObjectMigrationFn" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "SavedObjectUnsanitizedDoc" // // @public -export type SavedObjectMigrationFn = (doc: SavedObjectUnsanitizedDoc, log: SavedObjectsMigrationLogger) => SavedObjectUnsanitizedDoc; +export type SavedObjectMigrationFn = (doc: SavedObjectUnsanitizedDoc, context: SavedObjectMigrationContext) => SavedObjectUnsanitizedDoc; // @public export interface SavedObjectMigrationMap { @@ -1619,6 +1625,8 @@ export interface SavedObjectsClientWrapperOptions { client: SavedObjectsClientContract; // (undocumented) request: KibanaRequest; + // (undocumented) + typeRegistry: ISavedObjectTypeRegistry; } // @public @@ -2013,8 +2021,6 @@ export class SavedObjectsSchema { // @public export class SavedObjectsSerializer { - // Warning: (ae-forgotten-export) The symbol "ISavedObjectTypeRegistry" needs to be exported by the entry point index.d.ts - // // @internal constructor(registry: ISavedObjectTypeRegistry); generateRawId(namespace: string | undefined, type: string, id?: string): string; @@ -2026,6 +2032,7 @@ export class SavedObjectsSerializer { // @public export interface SavedObjectsServiceSetup { addClientWrapper: (priority: number, id: string, factory: SavedObjectsClientWrapperFactory) => void; + registerType: (type: SavedObjectsType) => void; setClientFactoryProvider: (clientFactoryProvider: SavedObjectsClientFactoryProvider) => void; } @@ -2035,6 +2042,7 @@ export interface SavedObjectsServiceStart { createScopedRepository: (req: KibanaRequest, extraTypes?: string[]) => ISavedObjectsRepository; createSerializer: () => SavedObjectsSerializer; getScopedClient: (req: KibanaRequest, options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract; + getTypeRegistry: () => ISavedObjectTypeRegistry; } // @public (undocumented) @@ -2069,7 +2077,7 @@ export interface SavedObjectsUpdateResponse extends Omit { }, }, }; + + const coreStart = coreMock.createStart(); + coreStart.savedObjects.getTypeRegistry.mockReturnValue(typeRegistry); + mockKbnServer = { newPlatform: { __internals: { kibanaMigrator: migrator, savedObjectsClientProvider: clientProvider, - typeRegistry, }, setup: { core: coreMock.createSetup(), }, start: { - core: coreMock.createStart(), + core: coreStart, }, }, server: mockServer, From 457783e8395b622de80f7c176c95172d5ce21c3b Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 26 Feb 2020 08:25:03 -0700 Subject: [PATCH 091/123] [kbn/ui-shared-deps] load base css file (#58520) Co-authored-by: Elastic Machine --- packages/kbn-ui-shared-deps/index.d.ts | 5 +++++ packages/kbn-ui-shared-deps/index.js | 1 + packages/kbn-ui-shared-deps/scripts/build.js | 7 +++++-- src/legacy/ui/ui_render/ui_render_mixin.js | 1 + tasks/config/karma.js | 1 + 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/kbn-ui-shared-deps/index.d.ts b/packages/kbn-ui-shared-deps/index.d.ts index 132445bbde745..7ee96050a1248 100644 --- a/packages/kbn-ui-shared-deps/index.d.ts +++ b/packages/kbn-ui-shared-deps/index.d.ts @@ -27,6 +27,11 @@ export const distDir: string; */ export const distFilename: string; +/** + * Filename of the unthemed css file in the distributable directory + */ +export const baseCssDistFilename: string; + /** * Filename of the dark-theme css file in the distributable directory */ diff --git a/packages/kbn-ui-shared-deps/index.js b/packages/kbn-ui-shared-deps/index.js index c7c004bd55794..d1bb93ddecd0a 100644 --- a/packages/kbn-ui-shared-deps/index.js +++ b/packages/kbn-ui-shared-deps/index.js @@ -21,6 +21,7 @@ const Path = require('path'); exports.distDir = Path.resolve(__dirname, 'target'); exports.distFilename = 'kbn-ui-shared-deps.js'; +exports.baseCssDistFilename = 'kbn-ui-shared-deps.css'; exports.lightCssDistFilename = 'kbn-ui-shared-deps.light.css'; exports.darkCssDistFilename = 'kbn-ui-shared-deps.dark.css'; exports.externals = { diff --git a/packages/kbn-ui-shared-deps/scripts/build.js b/packages/kbn-ui-shared-deps/scripts/build.js index 8b7c22dac24ff..e45b3dbed1748 100644 --- a/packages/kbn-ui-shared-deps/scripts/build.js +++ b/packages/kbn-ui-shared-deps/scripts/build.js @@ -64,8 +64,11 @@ run( }); compiler.hooks.watchRun.tap('report on start', () => { - process.stdout.cursorTo(0, 0); - process.stdout.clearScreenDown(); + if (process.stdout.isTTY) { + process.stdout.cursorTo(0, 0); + process.stdout.clearScreenDown(); + } + log.info('Running webpack compilation...'); }); diff --git a/src/legacy/ui/ui_render/ui_render_mixin.js b/src/legacy/ui/ui_render/ui_render_mixin.js index 21c10bb20962f..0a1b95c23450b 100644 --- a/src/legacy/ui/ui_render/ui_render_mixin.js +++ b/src/legacy/ui/ui_render/ui_render_mixin.js @@ -112,6 +112,7 @@ export function uiRenderMixin(kbnServer, server, config) { ); const styleSheetPaths = [ ...dllStyleChunks, + `${basePath}/bundles/kbn-ui-shared-deps/${UiSharedDeps.baseCssDistFilename}`, ...(darkMode ? [ `${basePath}/bundles/kbn-ui-shared-deps/${UiSharedDeps.darkCssDistFilename}`, diff --git a/tasks/config/karma.js b/tasks/config/karma.js index 9992dafed41c5..24e97aa081e51 100644 --- a/tasks/config/karma.js +++ b/tasks/config/karma.js @@ -64,6 +64,7 @@ module.exports = function(grunt) { ? `http://localhost:5610/bundles/tests.bundle.js` : `http://localhost:5610/bundles/tests.bundle.js?shards=${TOTAL_CI_SHARDS}&shard_num=${shardNum}`, + `http://localhost:5610/bundles/kbn-ui-shared-deps/${UiSharedDeps.baseCssDistFilename}`, // this causes tilemap tests to fail, probably because the eui styles haven't been // included in the karma harness a long some time, if ever // `http://localhost:5610/bundles/kbn-ui-shared-deps/${UiSharedDeps.lightCssDistFilename}`, From 4b8b9a42181e9ea8db0532f4827f5b98a687a7d8 Mon Sep 17 00:00:00 2001 From: Justin Juno <50022106+justinjunodev@users.noreply.github.com> Date: Wed, 26 Feb 2020 10:13:53 -0600 Subject: [PATCH 092/123] [DOCS] Add Homebrew start + stop instructions for Kibana (#58495) * add brew start and stop instructions to docs * add float to start-stop doc * Update start-stop.asciidoc Co-authored-by: Elastic Machine --- docs/setup/install/brew-running.asciidoc | 9 +++++++++ docs/setup/start-stop.asciidoc | 10 +++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 docs/setup/install/brew-running.asciidoc diff --git a/docs/setup/install/brew-running.asciidoc b/docs/setup/install/brew-running.asciidoc new file mode 100644 index 0000000000000..ba78dd1659d04 --- /dev/null +++ b/docs/setup/install/brew-running.asciidoc @@ -0,0 +1,9 @@ +==== Running Kibana with `brew services` + +With Homebrew, Kibana can be started and stopped as follows: + +[source,sh] +-------------------------------------------------- +brew services start elastic/tap/kibana-full +brew services stop elastic/tap/kibana-full +-------------------------------------------------- diff --git a/docs/setup/start-stop.asciidoc b/docs/setup/start-stop.asciidoc index 2bbc49d9e2ae2..2fcc440680f12 100644 --- a/docs/setup/start-stop.asciidoc +++ b/docs/setup/start-stop.asciidoc @@ -46,4 +46,12 @@ include::install/init-systemd.asciidoc[] include::install/rpm-init.asciidoc[] [float] -include::install/systemd.asciidoc[] \ No newline at end of file +include::install/systemd.asciidoc[] + +[float] +=== Homebrew packages + +If you installed {kib} with the Elastic Homebrew formulae, you can start and stop {kib} from the command line using `brew services`. + +[float] +include::install/brew-running.asciidoc[] From 32fb5c15325b27fe98b6cbace708d6bbb04bdc60 Mon Sep 17 00:00:00 2001 From: Pete Harverson Date: Wed, 26 Feb 2020 16:30:10 +0000 Subject: [PATCH 093/123] [ML] Fixes creation of a watch for an anomaly detection job (#58597) --- x-pack/legacy/plugins/ml/public/application/app.tsx | 2 -- .../create_watch_flyout/create_watch_service.js | 12 +++++++++--- .../create_watch_flyout/select_severity.tsx | 4 ++-- .../ml/public/application/util/dependency_cache.ts | 10 ---------- x-pack/legacy/plugins/ml/public/legacy.ts | 2 -- 5 files changed, 11 insertions(+), 19 deletions(-) diff --git a/x-pack/legacy/plugins/ml/public/application/app.tsx b/x-pack/legacy/plugins/ml/public/application/app.tsx index add27193deb77..3acb24ac6e173 100644 --- a/x-pack/legacy/plugins/ml/public/application/app.tsx +++ b/x-pack/legacy/plugins/ml/public/application/app.tsx @@ -24,7 +24,6 @@ export interface MlDependencies extends AppMountParameters { security: SecurityPluginSetup; __LEGACY: { XSRF: string; - APP_URL: string; }; } @@ -48,7 +47,6 @@ const App: FC = ({ coreStart, deps }) => { basePath: coreStart.http.basePath, savedObjectsClient: coreStart.savedObjects.client, XSRF: deps.__LEGACY.XSRF, - APP_URL: deps.__LEGACY.APP_URL, application: coreStart.application, http: coreStart.http, security: deps.security, diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/create_watch_service.js b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/create_watch_service.js index 887afeb3ba818..89589c98b52c2 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/create_watch_service.js +++ b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/create_watch_service.js @@ -9,9 +9,10 @@ import { http } from '../../../../services/http_service'; import emailBody from './email.html'; import emailInfluencersBody from './email_influencers.html'; +import { DEFAULT_WATCH_SEVERITY } from './select_severity'; import { watch } from './watch.js'; import { i18n } from '@kbn/i18n'; -import { getBasePath, getAppUrl } from '../../../../util/dependency_cache'; +import { getBasePath, getApplication } from '../../../../util/dependency_cache'; const compiledEmailBody = template(emailBody); const compiledEmailInfluencersBody = template(emailInfluencersBody); @@ -75,7 +76,10 @@ class CreateWatchService { this.config.interval = '20m'; this.config.watcherEditURL = ''; this.config.includeInfluencers = false; - this.config.threshold = { display: 'critical', val: 75 }; + + // Current implementation means that default needs to match that of the select severity control. + const { display, val } = DEFAULT_WATCH_SEVERITY; + this.config.threshold = { display, val }; } createNewWatch = function(jobId) { @@ -91,12 +95,13 @@ class CreateWatchService { watch.input.search.request.body.aggs.bucket_results.filter.range.anomaly_score.gte = this.config.threshold.val; if (this.config.includeEmail && this.config.email !== '') { + const { getUrlForApp } = getApplication(); const emails = this.config.email.split(','); emailSection.send_email.email.to = emails; // create the html by adding the variables to the compiled email body. emailSection.send_email.email.body.html = compiledEmailBody({ - serverAddress: getAppUrl(), + serverAddress: getUrlForApp('ml', { absolute: true }), influencersSection: this.config.includeInfluencers === true ? compiledEmailInfluencersBody({ @@ -153,6 +158,7 @@ class CreateWatchService { upstreamJSON: { id, type: 'json', + isNew: false, // Set to false, as we want to allow watches to be overwritten. watch, }, }; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/select_severity.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/select_severity.tsx index 8b0e7da2a5637..727830a58bb41 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/select_severity.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/select_severity.tsx @@ -78,7 +78,7 @@ function optionValueToThreshold(value: number) { return threshold; } -const TABLE_SEVERITY_DEFAULT = SEVERITY_OPTIONS[0]; +export const DEFAULT_WATCH_SEVERITY = SEVERITY_OPTIONS[3]; const getSeverityOptions = () => SEVERITY_OPTIONS.map(({ color, display, val }) => ({ @@ -114,7 +114,7 @@ interface Props { } export const SelectSeverity: FC = ({ onChange }) => { - const [severity, setSeverity] = useState(TABLE_SEVERITY_DEFAULT); + const [severity, setSeverity] = useState(DEFAULT_WATCH_SEVERITY); const onSeverityChange = (valueDisplay: string) => { const option = optionValueToThreshold(optionsMap[valueDisplay]); diff --git a/x-pack/legacy/plugins/ml/public/application/util/dependency_cache.ts b/x-pack/legacy/plugins/ml/public/application/util/dependency_cache.ts index f837d90dba8fe..6d1dfa96ca03e 100644 --- a/x-pack/legacy/plugins/ml/public/application/util/dependency_cache.ts +++ b/x-pack/legacy/plugins/ml/public/application/util/dependency_cache.ts @@ -36,7 +36,6 @@ export interface DependencyCache { basePath: IBasePath | null; savedObjectsClient: SavedObjectsClientContract | null; XSRF: string | null; - APP_URL: string | null; application: ApplicationStart | null; http: HttpStart | null; security: SecurityPluginSetup | null; @@ -56,7 +55,6 @@ const cache: DependencyCache = { basePath: null, savedObjectsClient: null, XSRF: null, - APP_URL: null, application: null, http: null, security: null, @@ -76,7 +74,6 @@ export function setDependencyCache(deps: Partial) { cache.basePath = deps.basePath || null; cache.savedObjectsClient = deps.savedObjectsClient || null; cache.XSRF = deps.XSRF || null; - cache.APP_URL = deps.APP_URL || null; cache.application = deps.application || null; cache.http = deps.http || null; } @@ -171,13 +168,6 @@ export function getXSRF() { return cache.XSRF; } -export function getAppUrl() { - if (cache.APP_URL === null) { - throw new Error("app url hasn't been initialized"); - } - return cache.APP_URL; -} - export function getApplication() { if (cache.application === null) { throw new Error("application hasn't been initialized"); diff --git a/x-pack/legacy/plugins/ml/public/legacy.ts b/x-pack/legacy/plugins/ml/public/legacy.ts index 40a1afa06b5a6..7dfcf6a99c213 100644 --- a/x-pack/legacy/plugins/ml/public/legacy.ts +++ b/x-pack/legacy/plugins/ml/public/legacy.ts @@ -18,8 +18,6 @@ export const setup = pluginInstance.setup(npSetup.core, { security: ((npSetup.plugins as unknown) as { security: SecurityPluginSetup }).security, // security isn't in the PluginsSetup interface, but does exist __LEGACY: { XSRF: chrome.getXsrfToken(), - // @ts-ignore getAppUrl is missing from chrome's definition - APP_URL: chrome.getAppUrl(), }, }); export const start = pluginInstance.start(npStart.core, npStart.plugins); From 613e4b9b15dcdd42db456655635daa0d1247e5a7 Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Wed, 26 Feb 2020 11:33:42 -0500 Subject: [PATCH 094/123] Median label shows "Median" instead of "50th percentile of" (#58521) * Median label shows "Median" instead of "50th percentile of" * Update test Co-authored-by: Elastic Machine --- .../public/search/aggs/metrics/median.test.ts | 18 +++++++++++++----- .../data/public/search/aggs/metrics/median.ts | 14 +++++--------- .../aggs/metrics/percentiles_get_value.ts | 2 +- .../functional/apps/visualize/_metric_chart.js | 2 +- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts index 9affb0e3b2814..4755a873e6977 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts @@ -47,7 +47,6 @@ describe('AggTypeMetricMedianProvider class', () => { schema: 'metric', params: { field: 'bytes', - percents: [70], }, }, ], @@ -58,12 +57,21 @@ describe('AggTypeMetricMedianProvider class', () => { it('requests the percentiles aggregation in the Elasticsearch query DSL', () => { const dsl: Record = aggConfigs.toDsl(); - expect(dsl.median.percentiles.percents).toEqual([70]); + expect(dsl.median.percentiles.field).toEqual('bytes'); + expect(dsl.median.percentiles.percents).toEqual([50]); }); - it('asks Elasticsearch for array-based values in the aggregation response', () => { - const dsl: Record = aggConfigs.toDsl(); + it('converts the response', () => { + const agg = aggConfigs.getResponseAggs()[0]; - expect(dsl.median.percentiles.keyed).toBeFalsy(); + expect( + agg.getValue({ + [agg.id]: { + values: { + '50.0': 10, + }, + }, + }) + ).toEqual(10); }); }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts index be080aaa5ee6f..53a5ffff418f1 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts @@ -43,17 +43,13 @@ export const medianMetricAgg = new MetricAggType({ name: 'field', type: 'field', filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE], - }, - { - name: 'percents', - default: [50], - }, - { write(agg, output) { - output.params.keyed = false; + output.params.field = agg.getParam('field').name; + output.params.percents = [50]; }, }, ], - getResponseAggs: percentilesMetricAgg.getResponseAggs, - getValue: percentilesMetricAgg.getValue, + getValue(agg, bucket) { + return bucket[agg.id].values['50.0']; + }, }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles_get_value.ts b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles_get_value.ts index c357d7bb0a903..980d969a8ea0c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles_get_value.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/metrics/percentiles_get_value.ts @@ -24,7 +24,7 @@ export const getPercentileValue = ( agg: TAggConfig, bucket: any ) => { - const { values } = bucket[agg.parentId] && bucket[agg.parentId]; + const { values } = bucket[agg.parentId]; const percentile: any = find(values, ({ key }) => key === agg.key); diff --git a/test/functional/apps/visualize/_metric_chart.js b/test/functional/apps/visualize/_metric_chart.js index 6a95f7553943c..dab9d2213b764 100644 --- a/test/functional/apps/visualize/_metric_chart.js +++ b/test/functional/apps/visualize/_metric_chart.js @@ -78,7 +78,7 @@ export default function({ getService, getPageObjects }) { }); it('should show Median', async function() { - const medianBytes = ['5,565.263', '50th percentile of bytes']; + const medianBytes = ['5,565.263', 'Median bytes']; // For now, only comparing the text label part of the metric log.debug('Aggregation = Median'); await PageObjects.visEditor.selectAggregation('Median', 'metrics'); From 8021fd887ab5f86ed17489e580d2c3cdc0cb9e84 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Wed, 26 Feb 2020 09:36:43 -0700 Subject: [PATCH 095/123] [Metrics UI] Custom Metrics for Inventory View (#58072) * [Metrics UI] Add custom metrics interface to Inventory View * WIP * Adding workflows for editing custom metrics * Polishing visual design * Removing extra text * Fixing types and return values * fixing i18n * Adding aria labels for clearity * Changing custom group by to match same width as custom metric * updating integration test for custom metrics * Fixing type def --- .../infra/common/http_api/snapshot_api.ts | 34 ++- .../metrics_and_groupby_toolbar_items.tsx | 11 +- .../infra/common/inventory_models/types.ts | 1 + .../common/saved_objects/inventory_view.ts | 32 +++ .../components/inventory/toolbars/toolbar.tsx | 10 +- .../inventory/toolbars/toolbar_wrapper.tsx | 6 +- .../components/nodes_overview/index.tsx | 7 +- .../components/waffle/custom_field_panel.tsx | 5 +- .../metric_control/custom_metric_form.tsx | 247 ++++++++++++++++++ .../metric_control/get_custom_metric_label.ts | 30 +++ .../waffle/metric_control/index.tsx | 199 ++++++++++++++ .../metric_control/metrics_context_menu.tsx | 75 ++++++ .../metric_control/metrics_edit_mode.tsx | 73 ++++++ .../waffle/metric_control/mode_switcher.tsx | 113 ++++++++ .../components/waffle/metric_control/types.ts | 7 + .../waffle/waffle_group_by_controls.tsx | 1 + .../waffle/waffle_inventory_switcher.tsx | 19 +- .../waffle/waffle_metric_controls.tsx | 97 ------- .../containers/waffle/with_waffle_options.tsx | 28 +- .../waffle/with_waffle_view_state.tsx | 9 +- .../pages/infrastructure/snapshot/toolbar.tsx | 2 + .../store/local/waffle_options/actions.ts | 9 +- .../store/local/waffle_options/reducer.ts | 14 +- .../store/local/waffle_options/selector.ts | 1 + .../server/lib/snapshot/query_helpers.ts | 31 ++- .../test/api_integration/apis/infra/waffle.ts | 45 +++- 26 files changed, 986 insertions(+), 120 deletions(-) create mode 100644 x-pack/plugins/infra/public/components/waffle/metric_control/custom_metric_form.tsx create mode 100644 x-pack/plugins/infra/public/components/waffle/metric_control/get_custom_metric_label.ts create mode 100644 x-pack/plugins/infra/public/components/waffle/metric_control/index.tsx create mode 100644 x-pack/plugins/infra/public/components/waffle/metric_control/metrics_context_menu.tsx create mode 100644 x-pack/plugins/infra/public/components/waffle/metric_control/metrics_edit_mode.tsx create mode 100644 x-pack/plugins/infra/public/components/waffle/metric_control/mode_switcher.tsx create mode 100644 x-pack/plugins/infra/public/components/waffle/metric_control/types.ts delete mode 100644 x-pack/plugins/infra/public/components/waffle/waffle_metric_controls.tsx diff --git a/x-pack/plugins/infra/common/http_api/snapshot_api.ts b/x-pack/plugins/infra/common/http_api/snapshot_api.ts index c7c15fd8af161..6b666b39b0094 100644 --- a/x-pack/plugins/infra/common/http_api/snapshot_api.ts +++ b/x-pack/plugins/infra/common/http_api/snapshot_api.ts @@ -54,16 +54,41 @@ export const SnapshotGroupByRT = rt.array( }) ); -export const SnapshotMetricInputRT = rt.type({ +export const SnapshotNamedMetricInputRT = rt.type({ type: SnapshotMetricTypeRT, }); +export const SNAPSHOT_CUSTOM_AGGREGATIONS = ['avg', 'max', 'min', 'rate'] as const; + +export type SnapshotCustomAggregation = typeof SNAPSHOT_CUSTOM_AGGREGATIONS[number]; + +const snapshotCustomAggregationKeys = SNAPSHOT_CUSTOM_AGGREGATIONS.reduce< + Record +>((acc, agg) => ({ ...acc, [agg]: null }), {} as Record); + +export const SnapshotCustomAggregationRT = rt.keyof(snapshotCustomAggregationKeys); + +export const SnapshotCustomMetricInputRT = rt.intersection([ + rt.type({ + type: rt.literal('custom'), + field: rt.string, + aggregation: SnapshotCustomAggregationRT, + id: rt.string, + }), + rt.partial({ + label: rt.string, + }), +]); + +export const SnapshotMetricInputRT = rt.union([ + SnapshotNamedMetricInputRT, + SnapshotCustomMetricInputRT, +]); + export const SnapshotRequestRT = rt.intersection([ rt.type({ timerange: InfraTimerangeInputRT, - metric: rt.type({ - type: SnapshotMetricTypeRT, - }), + metric: SnapshotMetricInputRT, groupBy: SnapshotGroupByRT, nodeType: ItemTypeRT, sourceId: rt.string, @@ -77,6 +102,7 @@ export const SnapshotRequestRT = rt.intersection([ export type SnapshotNodePath = rt.TypeOf; export type SnapshotMetricInput = rt.TypeOf; +export type SnapshotCustomMetricInput = rt.TypeOf; export type InfraTimerangeInput = rt.TypeOf; export type SnapshotNodeMetric = rt.TypeOf; export type SnapshotGroupBy = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/inventory_models/shared/compontents/metrics_and_groupby_toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/shared/compontents/metrics_and_groupby_toolbar_items.tsx index fcaedcdd080b8..738fce45ee99f 100644 --- a/x-pack/plugins/infra/common/inventory_models/shared/compontents/metrics_and_groupby_toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/shared/compontents/metrics_and_groupby_toolbar_items.tsx @@ -9,7 +9,7 @@ import { EuiFlexItem } from '@elastic/eui'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { ToolbarProps } from '../../../../public/components/inventory/toolbars/toolbar'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { WaffleMetricControls } from '../../../../public/components/waffle/waffle_metric_controls'; +import { WaffleMetricControls } from '../../../../public/components/waffle/metric_control'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { WaffleGroupByControls } from '../../../../public/components/waffle/waffle_group_by_controls'; import { @@ -25,7 +25,11 @@ interface Props extends ToolbarProps { } export const MetricsAndGroupByToolbarItems = (props: Props) => { - const metricOptions = useMemo(() => props.metricTypes.map(toMetricOpt), [props.metricTypes]); + const metricOptions = useMemo( + () => + props.metricTypes.map(toMetricOpt).filter(v => v) as Array<{ text: string; value: string }>, + [props.metricTypes] + ); const groupByOptions = useMemo(() => props.groupByFields.map(toGroupByOpt), [ props.groupByFields, @@ -35,9 +39,12 @@ export const MetricsAndGroupByToolbarItems = (props: Props) => { <> diff --git a/x-pack/plugins/infra/common/inventory_models/types.ts b/x-pack/plugins/infra/common/inventory_models/types.ts index 2f61b16fb3df8..a6773d0a07450 100644 --- a/x-pack/plugins/infra/common/inventory_models/types.ts +++ b/x-pack/plugins/infra/common/inventory_models/types.ts @@ -305,6 +305,7 @@ export const SnapshotMetricTypeRT = rt.keyof({ sqsMessagesSent: null, sqsMessagesEmpty: null, sqsOldestMessage: null, + custom: null, }); export type SnapshotMetricType = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/saved_objects/inventory_view.ts b/x-pack/plugins/infra/common/saved_objects/inventory_view.ts index 3ab9042947f97..bccffadc0a1ba 100644 --- a/x-pack/plugins/infra/common/saved_objects/inventory_view.ts +++ b/x-pack/plugins/infra/common/saved_objects/inventory_view.ts @@ -26,6 +26,18 @@ export const inventoryViewSavedObjectMappings: { type: { type: 'keyword', }, + field: { + type: 'keyword', + }, + aggregation: { + type: 'keyword', + }, + id: { + type: 'keyword', + }, + label: { + type: 'keyword', + }, }, }, groupBy: { @@ -56,6 +68,26 @@ export const inventoryViewSavedObjectMappings: { }, }, }, + customMetrics: { + type: 'nested', + properties: { + type: { + type: 'keyword', + }, + field: { + type: 'keyword', + }, + aggregation: { + type: 'keyword', + }, + id: { + type: 'keyword', + }, + label: { + type: 'keyword', + }, + }, + }, boundsOverride: { properties: { max: { diff --git a/x-pack/plugins/infra/public/components/inventory/toolbars/toolbar.tsx b/x-pack/plugins/infra/public/components/inventory/toolbars/toolbar.tsx index a2882a3cd3124..c59ab994a018c 100644 --- a/x-pack/plugins/infra/public/components/inventory/toolbars/toolbar.tsx +++ b/x-pack/plugins/infra/public/components/inventory/toolbars/toolbar.tsx @@ -7,7 +7,11 @@ import React, { FunctionComponent } from 'react'; import { Action } from 'typescript-fsa'; import { EuiFlexItem } from '@elastic/eui'; -import { SnapshotMetricInput, SnapshotGroupBy } from '../../../../common/http_api/snapshot_api'; +import { + SnapshotMetricInput, + SnapshotGroupBy, + SnapshotCustomMetricInput, +} from '../../../../common/http_api/snapshot_api'; import { InventoryCloudAccount } from '../../../../common/http_api/inventory_meta_api'; import { findToolbar } from '../../../../common/inventory_models/toolbars'; import { ToolbarWrapper } from './toolbar_wrapper'; @@ -35,6 +39,10 @@ export interface ToolbarProps { region: ReturnType; accounts: InventoryCloudAccount[]; regions: string[]; + customMetrics: ReturnType; + changeCustomMetrics: ( + payload: SnapshotCustomMetricInput[] + ) => Action; } const wrapToolbarItems = ( diff --git a/x-pack/plugins/infra/public/components/inventory/toolbars/toolbar_wrapper.tsx b/x-pack/plugins/infra/public/components/inventory/toolbars/toolbar_wrapper.tsx index 231030362438f..735539d063b01 100644 --- a/x-pack/plugins/infra/public/components/inventory/toolbars/toolbar_wrapper.tsx +++ b/x-pack/plugins/infra/public/components/inventory/toolbars/toolbar_wrapper.tsx @@ -37,6 +37,8 @@ export const ToolbarWrapper = (props: Props) => { nodeType, accountId, region, + customMetrics, + changeCustomMetrics, }) => props.children({ createDerivedIndexPattern, @@ -51,6 +53,8 @@ export const ToolbarWrapper = (props: Props) => { nodeType, region, accountId, + customMetrics, + changeCustomMetrics, }) } @@ -146,7 +150,7 @@ export const toGroupByOpt = (field: string) => ({ export const toMetricOpt = ( metric: SnapshotMetricType -): { text: string; value: SnapshotMetricType } => { +): { text: string; value: SnapshotMetricType } | undefined => { switch (metric) { case 'cpu': return { diff --git a/x-pack/plugins/infra/public/components/nodes_overview/index.tsx b/x-pack/plugins/infra/public/components/nodes_overview/index.tsx index 8cd3faabd1e12..4d61568a63b9f 100644 --- a/x-pack/plugins/infra/public/components/nodes_overview/index.tsx +++ b/x-pack/plugins/infra/public/components/nodes_overview/index.tsx @@ -19,9 +19,10 @@ import { InfraLoadingPanel } from '../loading'; import { Map } from '../waffle/map'; import { ViewSwitcher } from '../waffle/view_switcher'; import { TableView } from './table'; -import { SnapshotNode } from '../../../common/http_api/snapshot_api'; +import { SnapshotNode, SnapshotCustomMetricInputRT } from '../../../common/http_api/snapshot_api'; import { convertIntervalToString } from '../../utils/convert_interval_to_string'; import { InventoryItemType } from '../../../common/inventory_models/types'; +import { createFormatterForMetric } from '../metrics_explorer/helpers/create_formatter_for_metric'; interface Props { options: InfraWaffleMapOptions; @@ -211,6 +212,10 @@ export const NodesOverview = class extends React.Component { // TODO: Change this to a real implimentation using the tickFormatter from the prototype as an example. private formatter = (val: string | number) => { const { metric } = this.props.options; + if (SnapshotCustomMetricInputRT.is(metric)) { + const formatter = createFormatterForMetric(metric); + return formatter(val); + } const metricFormatter = get(METRIC_FORMATTERS, metric.type, METRIC_FORMATTERS.count); if (val == null) { return ''; diff --git a/x-pack/plugins/infra/public/components/waffle/custom_field_panel.tsx b/x-pack/plugins/infra/public/components/waffle/custom_field_panel.tsx index 15d8b8b0e42b8..d2dc535f6d6b3 100644 --- a/x-pack/plugins/infra/public/components/waffle/custom_field_panel.tsx +++ b/x-pack/plugins/infra/public/components/waffle/custom_field_panel.tsx @@ -50,10 +50,10 @@ export const CustomFieldPanel = class extends React.PureComponent helpText={i18n.translate('xpack.infra.waffle.customGroupByHelpText', { defaultMessage: 'This is the field used for the terms aggregation', })} - compressed + display="rowCompressed" + fullWidth > selectedOptions={this.state.selectedOptions} options={options} onChange={this.handleFieldSelection} + fullWidth isClearable={false} />
diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/custom_metric_form.tsx b/x-pack/plugins/infra/public/components/waffle/metric_control/custom_metric_form.tsx new file mode 100644 index 0000000000000..26e42061ed10b --- /dev/null +++ b/x-pack/plugins/infra/public/components/waffle/metric_control/custom_metric_form.tsx @@ -0,0 +1,247 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { useState, useCallback } from 'react'; +import uuid from 'uuid'; +import { + EuiForm, + EuiButton, + EuiButtonEmpty, + EuiFormRow, + EuiFieldText, + EuiComboBox, + EuiSelect, + EuiFlexGroup, + EuiFlexItem, + EuiText, + EuiPopoverTitle, +} from '@elastic/eui'; +import { IFieldType } from 'src/plugins/data/public'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + SnapshotCustomAggregation, + SnapshotCustomMetricInput, + SNAPSHOT_CUSTOM_AGGREGATIONS, + SnapshotCustomAggregationRT, +} from '../../../../common/http_api/snapshot_api'; +import { EuiTheme, withTheme } from '../../../../../../legacy/common/eui_styled_components'; + +interface SelectedOption { + label: string; +} + +const AGGREGATION_LABELS = { + ['avg']: i18n.translate('xpack.infra.waffle.customMetrics.aggregationLables.avg', { + defaultMessage: 'Average', + }), + ['max']: i18n.translate('xpack.infra.waffle.customMetrics.aggregationLables.max', { + defaultMessage: 'Max', + }), + ['min']: i18n.translate('xpack.infra.waffle.customMetrics.aggregationLables.min', { + defaultMessage: 'Min', + }), + ['rate']: i18n.translate('xpack.infra.waffle.customMetrics.aggregationLables.rate', { + defaultMessage: 'Rate', + }), +}; + +interface Props { + theme: EuiTheme; + metric?: SnapshotCustomMetricInput; + fields: IFieldType[]; + customMetrics: SnapshotCustomMetricInput[]; + onChange: (metric: SnapshotCustomMetricInput) => void; + onCancel: () => void; +} + +export const CustomMetricForm = withTheme( + ({ theme, onCancel, fields, onChange, metric }: Props) => { + const [label, setLabel] = useState(metric ? metric.label : void 0); + const [aggregation, setAggregation] = useState( + metric ? metric.aggregation : 'avg' + ); + const [field, setField] = useState(metric ? metric.field : void 0); + + const handleSubmit = useCallback(() => { + if (metric && aggregation && field) { + onChange({ + ...metric, + label, + aggregation, + field, + }); + } else if (aggregation && field) { + const newMetric: SnapshotCustomMetricInput = { + type: 'custom', + id: uuid.v1(), + label, + aggregation, + field, + }; + onChange(newMetric); + } + }, [metric, aggregation, field, onChange, label]); + + const handleLabelChange = useCallback( + e => { + setLabel(e.target.value); + }, + [setLabel] + ); + + const handleFieldChange = useCallback( + (selectedOptions: SelectedOption[]) => { + setField(selectedOptions[0].label); + }, + [setField] + ); + + const handleAggregationChange = useCallback( + e => { + const value = e.target.value; + const aggValue: SnapshotCustomAggregation = SnapshotCustomAggregationRT.is(value) + ? value + : 'avg'; + setAggregation(aggValue); + }, + [setAggregation] + ); + + const fieldOptions = fields + .filter(f => f.aggregatable && f.type === 'number' && !(field && field === f.name)) + .map(f => ({ label: f.name })); + + const aggregationOptions = SNAPSHOT_CUSTOM_AGGREGATIONS.map(k => ({ + text: AGGREGATION_LABELS[k as SnapshotCustomAggregation], + value: k, + })); + + const isSubmitDisabled = !field || !aggregation; + + const title = metric + ? i18n.translate('xpack.infra.waffle.customMetricPanelLabel.edit', { + defaultMessage: 'Edit custom metric', + }) + : i18n.translate('xpack.infra.waffle.customMetricPanelLabel.add', { + defaultMessage: 'Add custom metric', + }); + + const titleAriaLabel = metric + ? i18n.translate('xpack.infra.waffle.customMetricPanelLabel.editAriaLabel', { + defaultMessage: 'Back to custom metrics edit mode', + }) + : i18n.translate('xpack.infra.waffle.customMetricPanelLabel.addAriaLabel', { + defaultMessage: 'Back to metric picker', + }); + + return ( +
+ + + + {title} + + +
+ + + + + + + + of + + + + + + + + + + +
+
+ + + + + + +
+
+
+ ); + } +); diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/get_custom_metric_label.ts b/x-pack/plugins/infra/public/components/waffle/metric_control/get_custom_metric_label.ts new file mode 100644 index 0000000000000..4f88c1b29c1f2 --- /dev/null +++ b/x-pack/plugins/infra/public/components/waffle/metric_control/get_custom_metric_label.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { SnapshotCustomMetricInput } from '../../../../common/http_api/snapshot_api'; + +export const getCustomMetricLabel = (metric: SnapshotCustomMetricInput) => { + const METRIC_LABELS = { + avg: i18n.translate('xpack.infra.waffle.aggregationNames.avg', { + defaultMessage: 'Avg of {field}', + values: { field: metric.field }, + }), + max: i18n.translate('xpack.infra.waffle.aggregationNames.max', { + defaultMessage: 'Max of {field}', + values: { field: metric.field }, + }), + min: i18n.translate('xpack.infra.waffle.aggregationNames.min', { + defaultMessage: 'Min of {field}', + values: { field: metric.field }, + }), + rate: i18n.translate('xpack.infra.waffle.aggregationNames.rate', { + defaultMessage: 'Rate of {field}', + values: { field: metric.field }, + }), + }; + return metric.label ? metric.label : METRIC_LABELS[metric.aggregation]; +}; diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/index.tsx b/x-pack/plugins/infra/public/components/waffle/metric_control/index.tsx new file mode 100644 index 0000000000000..0f2034fe9cb25 --- /dev/null +++ b/x-pack/plugins/infra/public/components/waffle/metric_control/index.tsx @@ -0,0 +1,199 @@ +/* + * 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 { EuiFilterButton, EuiFilterGroup, EuiPopover } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import React, { useState, useCallback } from 'react'; +import { IFieldType } from 'src/plugins/data/public'; +import { + SnapshotMetricInput, + SnapshotCustomMetricInput, + SnapshotCustomMetricInputRT, +} from '../../../../common/http_api/snapshot_api'; +import { CustomMetricForm } from './custom_metric_form'; +import { getCustomMetricLabel } from './get_custom_metric_label'; +import { MetricsContextMenu } from './metrics_context_menu'; +import { ModeSwitcher } from './mode_switcher'; +import { MetricsEditMode } from './metrics_edit_mode'; +import { CustomMetricMode } from './types'; +import { SnapshotMetricType } from '../../../../common/inventory_models/types'; + +interface Props { + options: Array<{ text: string; value: string }>; + metric: SnapshotMetricInput; + fields: IFieldType[]; + onChange: (metric: SnapshotMetricInput) => void; + onChangeCustomMetrics: (metrics: SnapshotCustomMetricInput[]) => void; + customMetrics: SnapshotCustomMetricInput[]; +} + +export const WaffleMetricControls = ({ + fields, + onChange, + onChangeCustomMetrics, + metric, + options, + customMetrics, +}: Props) => { + const [isPopoverOpen, setPopoverState] = useState(false); + const [mode, setMode] = useState('pick'); + const [editModeCustomMetrics, setEditModeCustomMetrics] = useState( + [] + ); + const [editCustomMetric, setEditCustomMetric] = useState(); + const handleClose = useCallback(() => { + setPopoverState(false); + }, [setPopoverState]); + + const handleToggle = useCallback(() => { + setPopoverState(!isPopoverOpen); + }, [isPopoverOpen]); + + const handleCustomMetric = useCallback( + (newMetric: SnapshotCustomMetricInput) => { + onChangeCustomMetrics([...customMetrics, newMetric]); + onChange(newMetric); + setMode('pick'); + }, + [customMetrics, onChange, onChangeCustomMetrics, setMode] + ); + + const setModeToEdit = useCallback(() => { + setMode('edit'); + setEditModeCustomMetrics(customMetrics); + }, [customMetrics]); + + const setModeToAdd = useCallback(() => { + setMode('addMetric'); + }, [setMode]); + + const setModeToPick = useCallback(() => { + setMode('pick'); + setEditModeCustomMetrics([]); + }, [setMode]); + + const handleDeleteCustomMetric = useCallback( + (m: SnapshotCustomMetricInput) => { + // If the metric we are deleting is the currently selected metric + // we need to change to the default. + if (SnapshotCustomMetricInputRT.is(metric) && m.id === metric.id) { + onChange({ type: options[0].value as SnapshotMetricType }); + } + // Filter out the deleted metric from the editbale. + const newMetrics = editModeCustomMetrics.filter(v => v.id !== m.id); + setEditModeCustomMetrics(newMetrics); + }, + [editModeCustomMetrics, metric, onChange, options] + ); + + const handleEditCustomMetric = useCallback( + (currentMetric: SnapshotCustomMetricInput) => { + const newMetrics = customMetrics.map(m => (m.id === currentMetric.id && currentMetric) || m); + onChangeCustomMetrics(newMetrics); + setModeToPick(); + setEditCustomMetric(void 0); + setEditModeCustomMetrics([]); + }, + [customMetrics, onChangeCustomMetrics, setModeToPick] + ); + + const handleSelectMetricToEdit = useCallback( + (currentMetric: SnapshotCustomMetricInput) => { + setEditCustomMetric(currentMetric); + setMode('editMetric'); + }, + [setMode, setEditCustomMetric] + ); + + const handleSaveEdit = useCallback(() => { + onChangeCustomMetrics(editModeCustomMetrics); + setMode('pick'); + }, [editModeCustomMetrics, onChangeCustomMetrics]); + + if (!options.length || !metric.type) { + throw Error( + i18n.translate('xpack.infra.waffle.unableToSelectMetricErrorTitle', { + defaultMessage: 'Unable to select options or value for metric.', + }) + ); + } + + const id = SnapshotCustomMetricInputRT.is(metric) && metric.id ? metric.id : metric.type; + const currentLabel = SnapshotCustomMetricInputRT.is(metric) + ? getCustomMetricLabel(metric) + : options.find(o => o.value === id)?.text; + + if (!currentLabel) { + return null; + } + + const button = ( + + + + ); + + return ( + + + {mode === 'pick' ? ( + + ) : null} + {mode === 'addMetric' ? ( + + ) : null} + {mode === 'editMetric' ? ( + + ) : null} + {mode === 'edit' ? ( + + ) : null} + + + + ); +}; diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/metrics_context_menu.tsx b/x-pack/plugins/infra/public/components/waffle/metric_control/metrics_context_menu.tsx new file mode 100644 index 0000000000000..1aacf54244c37 --- /dev/null +++ b/x-pack/plugins/infra/public/components/waffle/metric_control/metrics_context_menu.tsx @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { useCallback } from 'react'; +import { EuiContextMenuPanelDescriptor, EuiContextMenu } from '@elastic/eui'; +import { + SnapshotMetricInput, + SnapshotCustomMetricInput, + SnapshotCustomMetricInputRT, +} from '../../../../common/http_api/snapshot_api'; +import { + SnapshotMetricTypeRT, + SnapshotMetricType, +} from '../../../../common/inventory_models/types'; +import { getCustomMetricLabel } from './get_custom_metric_label'; + +interface Props { + options: Array<{ text: string; value: string }>; + metric: SnapshotMetricInput; + onChange: (metric: SnapshotMetricInput) => void; + onClose: () => void; + customMetrics: SnapshotCustomMetricInput[]; +} + +export const MetricsContextMenu = ({ + onClose, + onChange, + metric, + options, + customMetrics, +}: Props) => { + const id = SnapshotCustomMetricInputRT.is(metric) && metric.id ? metric.id : metric.type; + + const handleClick = useCallback( + (val: string) => { + if (!SnapshotMetricTypeRT.is(val)) { + const selectedMetric = customMetrics.find(m => m.id === val); + if (selectedMetric) { + onChange(selectedMetric); + } + } else { + onChange({ type: val as SnapshotMetricType }); + } + onClose(); + }, + [customMetrics, onChange, onClose] + ); + + const panels: EuiContextMenuPanelDescriptor[] = [ + { + id: 0, + title: '', + items: [ + ...options.map(o => { + const icon = o.value === id ? 'check' : 'empty'; + const panel = { name: o.text, onClick: () => handleClick(o.value), icon }; + return panel; + }), + ...customMetrics.map(m => { + const icon = m.id === id ? 'check' : 'empty'; + const panel = { + name: getCustomMetricLabel(m), + onClick: () => handleClick(m.id), + icon, + }; + return panel; + }), + ], + }, + ]; + + return ; +}; diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/metrics_edit_mode.tsx b/x-pack/plugins/infra/public/components/waffle/metric_control/metrics_edit_mode.tsx new file mode 100644 index 0000000000000..ba1f46815db20 --- /dev/null +++ b/x-pack/plugins/infra/public/components/waffle/metric_control/metrics_edit_mode.tsx @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React from 'react'; +import { EuiFlexItem, EuiFlexGroup, EuiButtonIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { SnapshotCustomMetricInput } from '../../../../common/http_api/snapshot_api'; +import { getCustomMetricLabel } from './get_custom_metric_label'; +import { EuiTheme, withTheme } from '../../../../../../legacy/common/eui_styled_components'; + +interface Props { + theme: EuiTheme; + customMetrics: SnapshotCustomMetricInput[]; + options: Array<{ text: string; value: string }>; + onEdit: (metric: SnapshotCustomMetricInput) => void; + onDelete: (metric: SnapshotCustomMetricInput) => void; +} +const ICON_WIDTH = 36; + +export const MetricsEditMode = withTheme( + ({ theme, customMetrics, options, onEdit, onDelete }: Props) => { + return ( +
+ {options.map(option => ( +
+ {option.text} +
+ ))} + {customMetrics.map(metric => ( + + + onEdit(metric)} + aria-label={i18n.translate( + 'xpack.infra.waffle.customMetrics.editMode.editButtonAriaLabel', + { + defaultMessage: 'Edit custom metric for {name}', + values: { name: getCustomMetricLabel(metric) }, + } + )} + /> + + + {getCustomMetricLabel(metric)} + + + onDelete(metric)} + aria-label={i18n.translate( + 'xpack.infra.waffle.customMetrics.editMode.deleteAriaLabel', + { + defaultMessage: 'Delete custom metric for {name}', + values: { name: getCustomMetricLabel(metric) }, + } + )} + /> + + + ))} +
+ ); + } +); diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/mode_switcher.tsx b/x-pack/plugins/infra/public/components/waffle/metric_control/mode_switcher.tsx new file mode 100644 index 0000000000000..43bb904594c68 --- /dev/null +++ b/x-pack/plugins/infra/public/components/waffle/metric_control/mode_switcher.tsx @@ -0,0 +1,113 @@ +/* + * 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, EuiButtonEmpty, EuiButton } from '@elastic/eui'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { CustomMetricMode } from './types'; +import { SnapshotCustomMetricInput } from '../../../../common/http_api/snapshot_api'; +import { EuiTheme, withTheme } from '../../../../../../legacy/common/eui_styled_components'; + +interface Props { + theme: EuiTheme; + onEdit: () => void; + onAdd: () => void; + onSave: () => void; + onEditCancel: () => void; + mode: CustomMetricMode; + customMetrics: SnapshotCustomMetricInput[]; +} + +export const ModeSwitcher = withTheme( + ({ onSave, onEditCancel, onEdit, onAdd, mode, customMetrics, theme }: Props) => { + if (['editMetric', 'addMetric'].includes(mode)) { + return null; + } + return ( +
+ + {mode === 'edit' ? ( + <> + + + + + + + + + + + + ) : ( + <> + + + + + + + + + + + + )} + +
+ ); + } +); diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/types.ts b/x-pack/plugins/infra/public/components/waffle/metric_control/types.ts new file mode 100644 index 0000000000000..79e42b12f9976 --- /dev/null +++ b/x-pack/plugins/infra/public/components/waffle/metric_control/types.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 CustomMetricMode = 'pick' | 'addMetric' | 'editMetric' | 'edit'; diff --git a/x-pack/plugins/infra/public/components/waffle/waffle_group_by_controls.tsx b/x-pack/plugins/infra/public/components/waffle/waffle_group_by_controls.tsx index 81f82ec27b4a3..1a3cef591bc07 100644 --- a/x-pack/plugins/infra/public/components/waffle/waffle_group_by_controls.tsx +++ b/x-pack/plugins/infra/public/components/waffle/waffle_group_by_controls.tsx @@ -104,6 +104,7 @@ export const WaffleGroupByControls = class extends React.PureComponent void; changeGroupBy: (groupBy: SnapshotGroupBy) => void; changeMetric: (metric: SnapshotMetricInput) => void; + changeCustomMetrics: (metrics: SnapshotCustomMetricInput[]) => void; changeAccount: (id: string) => void; changeRegion: (name: string) => void; } @@ -38,6 +43,7 @@ export const WaffleInventorySwitcher: React.FC = ( changeMetric, changeAccount, changeRegion, + changeCustomMetrics, nodeType, }) => { const [isOpen, setIsOpen] = useState(false); @@ -48,6 +54,7 @@ export const WaffleInventorySwitcher: React.FC = ( closePopover(); changeNodeType(targetNodeType); changeGroupBy([]); + changeCustomMetrics([]); changeAccount(''); changeRegion(''); const inventoryModel = findInventoryModel(targetNodeType); @@ -55,7 +62,15 @@ export const WaffleInventorySwitcher: React.FC = ( type: inventoryModel.metrics.defaultSnapshot, }); }, - [closePopover, changeNodeType, changeGroupBy, changeMetric, changeAccount, changeRegion] + [ + closePopover, + changeNodeType, + changeGroupBy, + changeCustomMetrics, + changeAccount, + changeRegion, + changeMetric, + ] ); const goToHost = useCallback(() => goToNodeType('host'), [goToNodeType]); const goToK8 = useCallback(() => goToNodeType('pod'), [goToNodeType]); diff --git a/x-pack/plugins/infra/public/components/waffle/waffle_metric_controls.tsx b/x-pack/plugins/infra/public/components/waffle/waffle_metric_controls.tsx deleted file mode 100644 index f9e48730eaaf2..0000000000000 --- a/x-pack/plugins/infra/public/components/waffle/waffle_metric_controls.tsx +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - EuiContextMenu, - EuiContextMenuPanelDescriptor, - EuiFilterButton, - EuiFilterGroup, - EuiPopover, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React from 'react'; -import { SnapshotMetricInput } from '../../../common/http_api/snapshot_api'; -import { SnapshotMetricType } from '../../../common/inventory_models/types'; - -interface Props { - options: Array<{ text: string; value: SnapshotMetricType }>; - metric: SnapshotMetricInput; - onChange: (metric: SnapshotMetricInput) => void; -} - -const initialState = { - isPopoverOpen: false, -}; -type State = Readonly; - -export const WaffleMetricControls = class extends React.PureComponent { - public static displayName = 'WaffleMetricControls'; - public readonly state: State = initialState; - public render() { - const { metric, options } = this.props; - const value = metric.type; - - if (!options.length || !value) { - throw Error( - i18n.translate('xpack.infra.waffle.unableToSelectMetricErrorTitle', { - defaultMessage: 'Unable to select options or value for metric.', - }) - ); - } - const currentLabel = options.find(o => o.value === metric.type); - if (!currentLabel) { - return null; - } - const panels: EuiContextMenuPanelDescriptor[] = [ - { - id: 0, - title: '', - items: options.map(o => { - const icon = o.value === metric.type ? 'check' : 'empty'; - const panel = { name: o.text, onClick: this.handleClick(o.value), icon }; - return panel; - }), - }, - ]; - const button = ( - - - - ); - - return ( - - - - - - ); - } - private handleClose = () => { - this.setState({ isPopoverOpen: false }); - }; - - private handleToggle = () => { - this.setState(state => ({ isPopoverOpen: !state.isPopoverOpen })); - }; - - private handleClick = (value: SnapshotMetricType) => () => { - this.props.onChange({ type: value }); - this.handleClose(); - }; -}; diff --git a/x-pack/plugins/infra/public/containers/waffle/with_waffle_options.tsx b/x-pack/plugins/infra/public/containers/waffle/with_waffle_options.tsx index 45222b32aa51f..47dd6a5a73a73 100644 --- a/x-pack/plugins/infra/public/containers/waffle/with_waffle_options.tsx +++ b/x-pack/plugins/infra/public/containers/waffle/with_waffle_options.tsx @@ -14,7 +14,11 @@ import { State, waffleOptionsActions, waffleOptionsSelectors } from '../../store import { asChildFunctionRenderer } from '../../utils/typed_react'; import { bindPlainActionCreators } from '../../utils/typed_redux'; import { UrlStateContainer } from '../../utils/url_state'; -import { SnapshotMetricInput, SnapshotGroupBy } from '../../../common/http_api/snapshot_api'; +import { + SnapshotMetricInput, + SnapshotGroupBy, + SnapshotCustomMetricInputRT, +} from '../../../common/http_api/snapshot_api'; import { SnapshotMetricTypeRT, InventoryItemType, @@ -31,6 +35,7 @@ const selectOptionsUrlState = createSelector( waffleOptionsSelectors.selectAutoBounds, waffleOptionsSelectors.selectAccountId, waffleOptionsSelectors.selectRegion, + waffleOptionsSelectors.selectCustomMetrics, ( metric, view, @@ -40,7 +45,8 @@ const selectOptionsUrlState = createSelector( boundsOverride, autoBounds, accountId, - region + region, + customMetrics ) => ({ metric, groupBy, @@ -51,6 +57,7 @@ const selectOptionsUrlState = createSelector( autoBounds, accountId, region, + customMetrics, }) ); @@ -66,6 +73,7 @@ export const withWaffleOptions = connect( accountId: waffleOptionsSelectors.selectAccountId(state), region: waffleOptionsSelectors.selectRegion(state), urlState: selectOptionsUrlState(state), + customMetrics: waffleOptionsSelectors.selectCustomMetrics(state), }), bindPlainActionCreators({ changeMetric: waffleOptionsActions.changeMetric, @@ -77,6 +85,7 @@ export const withWaffleOptions = connect( changeAutoBounds: waffleOptionsActions.changeAutoBounds, changeAccount: waffleOptionsActions.changeAccount, changeRegion: waffleOptionsActions.changeRegion, + changeCustomMetrics: waffleOptionsActions.changeCustomMetrics, }) ); @@ -96,6 +105,7 @@ interface WaffleOptionsUrlState { auto?: ReturnType; accountId?: ReturnType; region?: ReturnType; + customMetrics?: ReturnType; } export const WithWaffleOptionsUrlState = () => ( @@ -111,6 +121,7 @@ export const WithWaffleOptionsUrlState = () => ( changeBoundsOverride, changeAccount, changeRegion, + changeCustomMetrics, }) => ( urlState={urlState} @@ -144,6 +155,9 @@ export const WithWaffleOptionsUrlState = () => ( if (newUrlState && newUrlState.region) { changeRegion(newUrlState.region); } + if (newUrlState && newUrlState.customMetrics) { + changeCustomMetrics(newUrlState.customMetrics); + } }} onInitialize={initialUrlState => { if (initialUrlState && initialUrlState.metric) { @@ -173,6 +187,9 @@ export const WithWaffleOptionsUrlState = () => ( if (initialUrlState && initialUrlState.region) { changeRegion(initialUrlState.region); } + if (initialUrlState && initialUrlState.customMetrics) { + changeCustomMetrics(initialUrlState.customMetrics); + } }} /> )} @@ -191,6 +208,7 @@ const mapToUrlState = (value: any): WaffleOptionsUrlState | undefined => auto: mapToAutoBoundsUrlState(value.autoBounds), accountId: value.accountId, region: value.region, + customMetrics: mapToCustomMetricsUrlState(value.customMetrics), } : undefined; @@ -232,6 +250,12 @@ const mapToCustomOptionsUrlState = (subject: any) => { : undefined; }; +const mapToCustomMetricsUrlState = (subject: any) => { + return subject && Array.isArray(subject) && subject.every(s => SnapshotCustomMetricInputRT.is(s)) + ? subject + : []; +}; + const mapToBoundsOverideUrlState = (subject: any) => { return subject != null && isNumber(subject.max) && isNumber(subject.min) ? subject : undefined; }; diff --git a/x-pack/plugins/infra/public/containers/waffle/with_waffle_view_state.tsx b/x-pack/plugins/infra/public/containers/waffle/with_waffle_view_state.tsx index 4e8a051bf8697..421c506166d04 100644 --- a/x-pack/plugins/infra/public/containers/waffle/with_waffle_view_state.tsx +++ b/x-pack/plugins/infra/public/containers/waffle/with_waffle_view_state.tsx @@ -30,6 +30,7 @@ const selectViewState = createSelector( waffleTimeSelectors.selectCurrentTime, waffleTimeSelectors.selectIsAutoReloading, waffleFilterSelectors.selectWaffleFilterQuery, + waffleOptionsSelectors.selectCustomMetrics, ( metric, view, @@ -40,7 +41,8 @@ const selectViewState = createSelector( autoBounds, time, autoReload, - filterQuery + filterQuery, + customMetrics ) => ({ time, autoReload, @@ -52,6 +54,7 @@ const selectViewState = createSelector( boundsOverride, autoBounds, filterQuery, + customMetrics, }) ); @@ -90,6 +93,9 @@ export const withWaffleViewState = connect( if (viewState.customOptions) { dispatch(waffleOptionsActions.changeCustomOptions(viewState.customOptions)); } + if (viewState.customMetrics) { + dispatch(waffleOptionsActions.changeCustomMetrics(viewState.customMetrics)); + } if (viewState.boundsOverride) { dispatch(waffleOptionsActions.changeBoundsOverride(viewState.boundsOverride)); } @@ -130,6 +136,7 @@ export interface WaffleViewState { nodeType?: ReturnType; view?: ReturnType; customOptions?: ReturnType; + customMetrics?: ReturnType; boundsOverride?: ReturnType; autoBounds?: ReturnType; time?: ReturnType; diff --git a/x-pack/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx b/x-pack/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx index a5780f44050e1..3606580e86504 100644 --- a/x-pack/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx +++ b/x-pack/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx @@ -29,6 +29,7 @@ export const SnapshotToolbar = () => ( changeGroupBy, changeAccount, changeRegion, + changeCustomMetrics, nodeType, }) => ( ( changeGroupBy={changeGroupBy} changeAccount={changeAccount} changeRegion={changeRegion} + changeCustomMetrics={changeCustomMetrics} /> )} diff --git a/x-pack/plugins/infra/public/store/local/waffle_options/actions.ts b/x-pack/plugins/infra/public/store/local/waffle_options/actions.ts index 4a1b45084b08a..88229c31b2056 100644 --- a/x-pack/plugins/infra/public/store/local/waffle_options/actions.ts +++ b/x-pack/plugins/infra/public/store/local/waffle_options/actions.ts @@ -5,7 +5,11 @@ */ import actionCreatorFactory from 'typescript-fsa'; -import { SnapshotGroupBy, SnapshotMetricInput } from '../../../../common/http_api/snapshot_api'; +import { + SnapshotGroupBy, + SnapshotMetricInput, + SnapshotCustomMetricInput, +} from '../../../../common/http_api/snapshot_api'; import { InventoryItemType } from '../../../../common/inventory_models/types'; import { InfraGroupByOptions, InfraWaffleMapBounds } from '../../../lib/lib'; @@ -20,3 +24,6 @@ export const changeBoundsOverride = actionCreator('CHANGE_ export const changeAutoBounds = actionCreator('CHANGE_AUTO_BOUNDS'); export const changeAccount = actionCreator('CHANGE_ACCOUNT'); export const changeRegion = actionCreator('CHANGE_REGION'); +export const changeCustomMetrics = actionCreator( + 'CHANGE_CUSTOM_METRICS' +); diff --git a/x-pack/plugins/infra/public/store/local/waffle_options/reducer.ts b/x-pack/plugins/infra/public/store/local/waffle_options/reducer.ts index 9d86ffe612a28..3789228a7c16b 100644 --- a/x-pack/plugins/infra/public/store/local/waffle_options/reducer.ts +++ b/x-pack/plugins/infra/public/store/local/waffle_options/reducer.ts @@ -6,7 +6,11 @@ import { combineReducers } from 'redux'; import { reducerWithInitialState } from 'typescript-fsa-reducers'; -import { SnapshotMetricInput, SnapshotGroupBy } from '../../../../common/http_api/snapshot_api'; +import { + SnapshotMetricInput, + SnapshotGroupBy, + SnapshotCustomMetricInput, +} from '../../../../common/http_api/snapshot_api'; import { InfraGroupByOptions, InfraWaffleMapBounds } from '../../../lib/lib'; import { changeAutoBounds, @@ -18,6 +22,7 @@ import { changeView, changeAccount, changeRegion, + changeCustomMetrics, } from './actions'; import { InventoryItemType } from '../../../../common/inventory_models/types'; @@ -31,6 +36,7 @@ export interface WaffleOptionsState { autoBounds: boolean; accountId: string; region: string; + customMetrics: SnapshotCustomMetricInput[]; } export const initialWaffleOptionsState: WaffleOptionsState = { @@ -43,6 +49,7 @@ export const initialWaffleOptionsState: WaffleOptionsState = { autoBounds: true, accountId: '', region: '', + customMetrics: [], }; const currentMetricReducer = reducerWithInitialState(initialWaffleOptionsState.metric).case( @@ -88,6 +95,10 @@ const currentRegionReducer = reducerWithInitialState(initialWaffleOptionsState.r (current, target) => target ); +const currentCustomMetricsReducer = reducerWithInitialState( + initialWaffleOptionsState.customMetrics +).case(changeCustomMetrics, (current, target) => target); + export const waffleOptionsReducer = combineReducers({ metric: currentMetricReducer, groupBy: currentGroupByReducer, @@ -98,4 +109,5 @@ export const waffleOptionsReducer = combineReducers({ autoBounds: currentAutoBoundsReducer, accountId: currentAccountIdReducer, region: currentRegionReducer, + customMetrics: currentCustomMetricsReducer, }); diff --git a/x-pack/plugins/infra/public/store/local/waffle_options/selector.ts b/x-pack/plugins/infra/public/store/local/waffle_options/selector.ts index 255fbd5ec4266..4487af156df97 100644 --- a/x-pack/plugins/infra/public/store/local/waffle_options/selector.ts +++ b/x-pack/plugins/infra/public/store/local/waffle_options/selector.ts @@ -15,3 +15,4 @@ export const selectBoundsOverride = (state: WaffleOptionsState) => state.boundsO export const selectAutoBounds = (state: WaffleOptionsState) => state.autoBounds; export const selectAccountId = (state: WaffleOptionsState) => state.accountId; export const selectRegion = (state: WaffleOptionsState) => state.region; +export const selectCustomMetrics = (state: WaffleOptionsState) => state.customMetrics; diff --git a/x-pack/plugins/infra/server/lib/snapshot/query_helpers.ts b/x-pack/plugins/infra/server/lib/snapshot/query_helpers.ts index 44d32c7b915a8..383dc9a773abe 100644 --- a/x-pack/plugins/infra/server/lib/snapshot/query_helpers.ts +++ b/x-pack/plugins/infra/server/lib/snapshot/query_helpers.ts @@ -8,7 +8,16 @@ import { i18n } from '@kbn/i18n'; import { findInventoryModel, findInventoryFields } from '../../../common/inventory_models/index'; import { InfraSnapshotRequestOptions } from './types'; import { getIntervalInSeconds } from '../../utils/get_interval_in_seconds'; -import { SnapshotModelRT, SnapshotModel } from '../../../common/inventory_models/types'; +import { + SnapshotModelRT, + SnapshotModel, + InventoryItemType, +} from '../../../common/inventory_models/types'; +import { + SnapshotMetricInput, + SnapshotCustomMetricInputRT, +} from '../../../common/http_api/snapshot_api'; +import { networkTraffic } from '../../../common/inventory_models/shared/metrics/snapshot/network_traffic'; interface GroupBySource { [id: string]: { @@ -45,9 +54,25 @@ export const getMetricsSources = (options: InfraSnapshotRequestOptions) => { return [{ id: { terms: { field: fields.id } } }]; }; +export const metricToAggregation = (nodeType: InventoryItemType, metric: SnapshotMetricInput) => { + const inventoryModel = findInventoryModel(nodeType); + if (SnapshotCustomMetricInputRT.is(metric)) { + if (metric.aggregation === 'rate') { + return networkTraffic(metric.type, metric.field); + } + return { + custom: { + [metric.aggregation]: { + field: metric.field, + }, + }, + }; + } + return inventoryModel.metrics.snapshot?.[metric.type]; +}; + export const getMetricsAggregations = (options: InfraSnapshotRequestOptions): SnapshotModel => { - const inventoryModel = findInventoryModel(options.nodeType); - const aggregation = inventoryModel.metrics.snapshot?.[options.metric.type]; + const aggregation = metricToAggregation(options.nodeType, options.metric); if (!SnapshotModelRT.is(aggregation)) { throw new Error( i18n.translate('xpack.infra.snapshot.missingSnapshotMetricError', { diff --git a/x-pack/test/api_integration/apis/infra/waffle.ts b/x-pack/test/api_integration/apis/infra/waffle.ts index 80fea1cdcd295..3413fc283556c 100644 --- a/x-pack/test/api_integration/apis/infra/waffle.ts +++ b/x-pack/test/api_integration/apis/infra/waffle.ts @@ -14,12 +14,15 @@ import { InfraSnapshotGroupbyInput, } from '../../../../plugins/infra/server/graphql/types'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { SnapshotNodeResponse } from '../../../../plugins/infra/common/http_api/snapshot_api'; +import { + SnapshotNodeResponse, + SnapshotMetricInput, +} from '../../../../plugins/infra/common/http_api/snapshot_api'; import { DATES } from './constants'; interface SnapshotRequest { filterQuery?: string | null; - metric: InfraSnapshotMetricInput; + metric: SnapshotMetricInput; groupBy: InfraSnapshotGroupbyInput[]; nodeType: InfraNodeType; sourceId: string; @@ -197,6 +200,44 @@ export default function({ getService }: FtrProviderContext) { }); }); + it('should work with custom metrics', async () => { + const data = await fetchSnapshot({ + sourceId: 'default', + timerange: { + to: max, + from: min, + interval: '1m', + }, + metric: { + type: 'custom', + field: 'system.cpu.user.pct', + aggregation: 'avg', + id: '1', + } as SnapshotMetricInput, + nodeType: 'host' as InfraNodeType, + groupBy: [], + }); + + const snapshot = data; + expect(snapshot).to.have.property('nodes'); + if (snapshot) { + const { nodes } = snapshot; + expect(nodes.length).to.equal(1); + const firstNode = first(nodes); + expect(firstNode).to.have.property('path'); + expect(firstNode.path.length).to.equal(1); + expect(first(firstNode.path)).to.have.property('value', 'demo-stack-mysql-01'); + expect(first(firstNode.path)).to.have.property('label', 'demo-stack-mysql-01'); + expect(firstNode).to.have.property('metric'); + expect(firstNode.metric).to.eql({ + name: 'custom', + value: 0.0041964285714285714, + max: 0.0041964285714285714, + avg: 0.0006994047619047619, + }); + } + }); + it('should basically work with 1 grouping', () => { const resp = fetchSnapshot({ sourceId: 'default', From e97b451cc186e47a4621b85cf2bd814a8529c0b6 Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Wed, 26 Feb 2020 16:42:15 +0000 Subject: [PATCH 096/123] [SIEM] add custom reputation link (#57814) * add custom reputation link * fix unit test * add number of limitation to reputation links * fix dependency * apply defaultFieldRendererOverflow to reputation link * fix unit test * fix url template * fix display links * fix types * fix for review * update test case * update snapshot * add icons and tooltips * fix style * update test * add external link component * update test * fix types * fix style * update snapshot * remove useMemo * update description * code review * review II * code review * update description * fix unit test * fix unit test * fix unit test * fix unit test * fix types * fix styles * fix style * fix style * fix review Co-authored-by: Elastic Machine --- .../legacy/plugins/siem/common/constants.ts | 9 + x-pack/legacy/plugins/siem/index.ts | 15 + .../field_renderers.test.tsx.snap | 20 +- .../field_renderers/field_renderers.tsx | 111 +- .../public/components/links/index.test.tsx | 365 +- .../siem/public/components/links/index.tsx | 203 +- .../__snapshots__/zeek_details.test.tsx.snap | 3261 +++++++++++++++++ .../body/renderers/zeek/zeek_details.test.tsx | 5 +- .../renderers/zeek/zeek_signature.test.tsx | 11 +- .../body/renderers/zeek/zeek_signature.tsx | 10 +- .../step_about_rule/helpers.test.ts | 18 + 11 files changed, 3876 insertions(+), 152 deletions(-) create mode 100644 x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/helpers.test.ts diff --git a/x-pack/legacy/plugins/siem/common/constants.ts b/x-pack/legacy/plugins/siem/common/constants.ts index 0d9e092e21d82..2a30293c244af 100644 --- a/x-pack/legacy/plugins/siem/common/constants.ts +++ b/x-pack/legacy/plugins/siem/common/constants.ts @@ -38,6 +38,15 @@ export const NEWS_FEED_URL_SETTING = 'siem:newsFeedUrl'; /** The default value for News feed widget */ export const NEWS_FEED_URL_SETTING_DEFAULT = 'https://feeds.elastic.co/security-solution'; +/** This Kibana Advanced Setting specifies the URLs of `IP Reputation Links`*/ +export const IP_REPUTATION_LINKS_SETTING = 'siem:ipReputationLinks'; + +/** The default value for `IP Reputation Links` */ +export const IP_REPUTATION_LINKS_SETTING_DEFAULT = `[ + { "name": "virustotal.com", "url_template": "https://www.virustotal.com/gui/search/{{ip}}" }, + { "name": "talosIntelligence.com", "url_template": "https://talosintelligence.com/reputation_center/lookup?search={{ip}}" } +]`; + /** * Id for the signals alerting type */ diff --git a/x-pack/legacy/plugins/siem/index.ts b/x-pack/legacy/plugins/siem/index.ts index 731ef10aa225e..db398821aecfd 100644 --- a/x-pack/legacy/plugins/siem/index.ts +++ b/x-pack/legacy/plugins/siem/index.ts @@ -28,6 +28,8 @@ import { NEWS_FEED_URL_SETTING, NEWS_FEED_URL_SETTING_DEFAULT, SIGNALS_INDEX_KEY, + IP_REPUTATION_LINKS_SETTING, + IP_REPUTATION_LINKS_SETTING_DEFAULT, } from './common/constants'; import { defaultIndexPattern } from './default_index_pattern'; import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/utils'; @@ -144,6 +146,19 @@ export const siem = (kibana: any) => { category: ['siem'], requiresPageReload: true, }, + [IP_REPUTATION_LINKS_SETTING]: { + name: i18n.translate('xpack.siem.uiSettings.ipReputationLinks', { + defaultMessage: 'IP Reputation Links', + }), + value: IP_REPUTATION_LINKS_SETTING_DEFAULT, + type: 'json', + description: i18n.translate('xpack.siem.uiSettings.ipReputationLinksDescription', { + defaultMessage: + 'Array of URL templates to build the list of reputation URLs to be displayed on the IP Details page.', + }), + category: ['siem'], + requiresPageReload: true, + }, }, mappings: savedObjectMappings, }, diff --git a/x-pack/legacy/plugins/siem/public/components/field_renderers/__snapshots__/field_renderers.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/field_renderers/__snapshots__/field_renderers.test.tsx.snap index 2ff93b2ecada4..59010ab80af63 100644 --- a/x-pack/legacy/plugins/siem/public/components/field_renderers/__snapshots__/field_renderers.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/field_renderers/__snapshots__/field_renderers.test.tsx.snap @@ -122,25 +122,17 @@ exports[`Field Renderers #reputationRenderer it renders correctly against snapsh - - virustotal.com - - , - - talosIntelligence.com - + /> `; exports[`Field Renderers #whoisRenderer it renders correctly against snapshot 1`] = ` - iana.org - + `; diff --git a/x-pack/legacy/plugins/siem/public/components/field_renderers/field_renderers.tsx b/x-pack/legacy/plugins/siem/public/components/field_renderers/field_renderers.tsx index 80d68dfe1b731..222eef515958c 100644 --- a/x-pack/legacy/plugins/siem/public/components/field_renderers/field_renderers.tsx +++ b/x-pack/legacy/plugins/siem/public/components/field_renderers/field_renderers.tsx @@ -15,7 +15,7 @@ import { escapeDataProviderId } from '../drag_and_drop/helpers'; import { DefaultDraggable } from '../draggables'; import { getEmptyTagValue } from '../empty_value'; import { FormattedRelativePreferenceDate } from '../formatted_date'; -import { HostDetailsLink, ReputationLink, VirusTotalLink, WhoIsLink } from '../links'; +import { HostDetailsLink, ReputationLink, WhoIsLink, ReputationLinkSetting } from '../links'; import { Spacer } from '../page'; import * as i18n from '../page/network/ip_overview/translations'; @@ -132,11 +132,7 @@ export const hostNameRenderer = (host: HostEcsFields, ipFilter?: string): React. export const whoisRenderer = (ip: string) => {i18n.VIEW_WHOIS}; export const reputationRenderer = (ip: string): React.ReactElement => ( - <> - {i18n.VIEW_VIRUS_TOTAL} - {', '} - {i18n.VIEW_TALOS_INTELLIGENCE} - + ); interface DefaultFieldRendererProps { @@ -148,73 +144,78 @@ interface DefaultFieldRendererProps { moreMaxHeight?: string; } +type OverflowRenderer = (item: string | ReputationLinkSetting) => JSX.Element; + // TODO: This causes breaks between elements until the ticket below is fixed // https://github.com/elastic/ingest-dev/issues/474 -export const DefaultFieldRenderer = React.memo( - ({ - attrName, - displayCount = 1, - idPrefix, - moreMaxHeight = DEFAULT_MORE_MAX_HEIGHT, - render, - rowItems, - }) => { - if (rowItems != null && rowItems.length > 0) { - const draggables = rowItems.slice(0, displayCount).map((rowItem, index) => { - const id = escapeDataProviderId( - `default-field-renderer-default-draggable-${idPrefix}-${attrName}-${rowItem}` - ); - return ( - - {index !== 0 && ( - <> - {','} - - - )} +export const DefaultFieldRendererComponent: React.FC = ({ + attrName, + displayCount = 1, + idPrefix, + moreMaxHeight = DEFAULT_MORE_MAX_HEIGHT, + render, + rowItems, +}) => { + if (rowItems != null && rowItems.length > 0) { + const draggables = rowItems.slice(0, displayCount).map((rowItem, index) => { + const id = escapeDataProviderId( + `default-field-renderer-default-draggable-${idPrefix}-${attrName}-${rowItem}` + ); + return ( + + {index !== 0 && ( + <> + {','} + + + )} + {typeof rowItem === 'string' && ( {render ? render(rowItem) : rowItem} - - ); - }); - - return draggables.length > 0 ? ( - - {draggables}{' '} - { - - } - - ) : ( - getEmptyTagValue() + )} + ); - } else { - return getEmptyTagValue(); - } + }); + + return draggables.length > 0 ? ( + + {draggables} + + + + + ) : ( + getEmptyTagValue() + ); + } else { + return getEmptyTagValue(); } -); +}; + +export const DefaultFieldRenderer = React.memo(DefaultFieldRendererComponent); DefaultFieldRenderer.displayName = 'DefaultFieldRenderer'; +type RowItemTypes = string | ReputationLinkSetting; interface DefaultFieldRendererOverflowProps { - rowItems: string[]; + rowItems: string[] | ReputationLinkSetting[]; idPrefix: string; - render?: (item: string) => React.ReactNode; + render?: (item: RowItemTypes) => React.ReactNode; overflowIndexStart?: number; moreMaxHeight: string; } interface MoreContainerProps { idPrefix: string; - render?: (item: string) => React.ReactNode; - rowItems: string[]; + render?: (item: RowItemTypes) => React.ReactNode; + rowItems: RowItemTypes[]; moreMaxHeight: string; overflowIndexStart: number; } diff --git a/x-pack/legacy/plugins/siem/public/components/links/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/links/index.test.tsx index ceef7e353b521..d2d1d6569854d 100644 --- a/x-pack/legacy/plugins/siem/public/components/links/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/links/index.test.tsx @@ -4,24 +4,32 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mount } from 'enzyme'; +import { mount, shallow, ShallowWrapper } from 'enzyme'; import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { encodeIpv6 } from '../../lib/helpers'; +import { useUiSetting$ } from '../../lib/kibana'; import { GoogleLink, HostDetailsLink, IPDetailsLink, ReputationLink, - VirusTotalLink, WhoIsLink, CertificateFingerprintLink, Ja3FingerprintLink, PortOrServiceNameLink, + DEFAULT_NUMBER_OF_LINK, + ExternalLink, } from '.'; +jest.mock('../../lib/kibana', () => { + return { + useUiSetting$: jest.fn(), + }; +}); + describe('Custom Links', () => { const hostName = 'Host Name'; const ipv4 = '192.0.2.255'; @@ -101,53 +109,332 @@ describe('Custom Links', () => { }); }); - describe('ReputationLink', () => { - test('it renders link text', () => { - const wrapper = mountWithIntl( - {'Example Link'} - ); - expect(wrapper.text()).toEqual('Example Link'); - }); + describe('External Link', () => { + const mockLink = 'https://www.virustotal.com/gui/search/'; + const mockLinkName = 'Link'; + let wrapper: ShallowWrapper; - test('it renders correct href', () => { - const wrapper = mountWithIntl( - {'Example Link'} - ); - expect(wrapper.find('a').prop('href')).toEqual( - 'https://www.talosintelligence.com/reputation_center/lookup?search=192.0.2.0' - ); + describe('render', () => { + beforeAll(() => { + wrapper = shallow( + + {mockLinkName} + + ); + }); + + test('it renders tooltip', () => { + expect(wrapper.find('[data-test-subj="externalLinkTooltip"]').exists()).toBeTruthy(); + }); + + test('it renders ExternalLinkIcon', () => { + expect(wrapper.find('[data-test-subj="externalLinkIcon"]').exists()).toBeTruthy(); + }); + + test('it renders correct url', () => { + expect(wrapper.find('[data-test-subj="externalLink"]').prop('href')).toEqual(mockLink); + }); + + test('it renders comma if id is given', () => { + expect(wrapper.find('[data-test-subj="externalLinkComma"]').exists()).toBeTruthy(); + }); }); - test("it encodes ", () => { - const wrapper = mountWithIntl( - alert('XSS')"}>{'Example Link'} - ); - expect(wrapper.find('a').prop('href')).toEqual( - "https://www.talosintelligence.com/reputation_center/lookup?search=%3Cscript%3Ealert('XSS')%3C%2Fscript%3E" - ); + describe('not render', () => { + test('it should not render if childen prop is not given', () => { + wrapper = shallow( + + ); + expect(wrapper.find('[data-test-subj="externalLinkTooltip"]').exists()).toBeFalsy(); + }); + + test('it should not render if url prop is not given', () => { + wrapper = shallow( + + ); + expect(wrapper.find('[data-test-subj="externalLinkTooltip"]').exists()).toBeFalsy(); + }); + + test('it should not render if url prop is invalid', () => { + wrapper = shallow( + + ); + expect(wrapper.find('[data-test-subj="externalLinkTooltip"]').exists()).toBeFalsy(); + }); + + test('it should not render comma if id is not given', () => { + wrapper = shallow( + + {mockLinkName} + + ); + expect(wrapper.find('[data-test-subj="externalLinkComma"]').exists()).toBeFalsy(); + }); + + test('it should not render comma for the last item', () => { + wrapper = shallow( + + {mockLinkName} + + ); + expect(wrapper.find('[data-test-subj="externalLinkComma"]').exists()).toBeFalsy(); + }); }); + + describe.each<[number, number, number, boolean]>([ + [0, 2, 5, true], + [1, 2, 5, false], + [2, 2, 5, false], + [3, 2, 5, false], + [4, 2, 5, false], + [5, 2, 5, false], + ])( + 'renders Comma when overflowIndex is smaller than allItems limit', + (idx, overflowIndexStart, allItemsLimit, showComma) => { + beforeAll(() => { + wrapper = shallow( + + {mockLinkName} + + ); + }); + + test(`should render Comma if current id (${idx}) is smaller than the index of last visible item`, () => { + expect(wrapper.find('[data-test-subj="externalLinkComma"]').exists()).toEqual(showComma); + }); + } + ); + + describe.each<[number, number, number, boolean]>([ + [0, 5, 4, true], + [1, 5, 4, true], + [2, 5, 4, true], + [3, 5, 4, false], + [4, 5, 4, false], + [5, 5, 4, false], + ])( + 'When overflowIndex is grater than allItems limit', + (idx, overflowIndexStart, allItemsLimit, showComma) => { + beforeAll(() => { + wrapper = shallow( + + {mockLinkName} + + ); + }); + + test(`Current item (${idx}) should render Comma execpt the last item`, () => { + expect(wrapper.find('[data-test-subj="externalLinkComma"]').exists()).toEqual(showComma); + }); + } + ); + + describe.each<[number, number, number, boolean]>([ + [0, 5, 5, true], + [1, 5, 5, true], + [2, 5, 5, true], + [3, 5, 5, true], + [4, 5, 5, false], + [5, 5, 5, false], + ])( + 'when overflowIndex equals to allItems limit', + (idx, overflowIndexStart, allItemsLimit, showComma) => { + beforeAll(() => { + wrapper = shallow( + + {mockLinkName} + + ); + }); + + test(`Current item (${idx}) should render Comma correctly`, () => { + expect(wrapper.find('[data-test-subj="externalLinkComma"]').exists()).toEqual(showComma); + }); + } + ); }); - describe('VirusTotalLink', () => { - test('it renders sha passed in as value', () => { - const wrapper = mountWithIntl({'Example Link'}); - expect(wrapper.text()).toEqual('Example Link'); + describe('ReputationLink', () => { + const mockCustomizedReputationLinks = [ + { name: 'Link 1', url_template: 'https://www.virustotal.com/gui/search/{{ip}}' }, + { + name: 'Link 2', + url_template: 'https://talosintelligence.com/reputation_center/lookup?search={{ip}}', + }, + { name: 'Link 3', url_template: 'https://www.virustotal.com/gui/search/{{ip}}' }, + { + name: 'Link 4', + url_template: 'https://talosintelligence.com/reputation_center/lookup?search={{ip}}', + }, + { name: 'Link 5', url_template: 'https://www.virustotal.com/gui/search/{{ip}}' }, + { + name: 'Link 6', + url_template: 'https://talosintelligence.com/reputation_center/lookup?search={{ip}}', + }, + ]; + const mockDefaultReputationLinks = mockCustomizedReputationLinks.slice(0, 2); + + describe('links property', () => { + beforeEach(() => { + (useUiSetting$ as jest.Mock).mockReset(); + (useUiSetting$ as jest.Mock).mockReturnValue([mockDefaultReputationLinks]); + }); + + test('it renders default link text', () => { + const wrapper = shallow(); + wrapper.find('[data-test-subj="externalLink"]').forEach((node, idx) => { + expect(node.at(idx).text()).toEqual(mockDefaultReputationLinks[idx].name); + }); + }); + + test('it renders customized link text', () => { + (useUiSetting$ as jest.Mock).mockReset(); + (useUiSetting$ as jest.Mock).mockReturnValue([mockCustomizedReputationLinks]); + const wrapper = shallow(); + wrapper.find('[data-test-subj="externalLink"]').forEach((node, idx) => { + expect(node.at(idx).text()).toEqual(mockCustomizedReputationLinks[idx].name); + }); + }); + + test('it renders correct href', () => { + const wrapper = shallow(); + wrapper.find('[data-test-subj="externalLink"]').forEach((node, idx) => { + expect(node.prop('href')).toEqual( + mockDefaultReputationLinks[idx].url_template.replace('{{ip}}', '192.0.2.0') + ); + }); + }); }); - test('it renders sha passed in as link', () => { - const wrapper = mountWithIntl( - {'Example Link'} - ); - expect(wrapper.find('a').prop('href')).toEqual('https://www.virustotal.com/#/search/abc'); + describe('number of links', () => { + beforeAll(() => { + (useUiSetting$ as jest.Mock).mockReset(); + (useUiSetting$ as jest.Mock).mockReturnValue([mockCustomizedReputationLinks]); + }); + + afterEach(() => { + (useUiSetting$ as jest.Mock).mockClear(); + }); + + test('it renders correct number of links by default', () => { + const wrapper = mountWithIntl(); + expect(wrapper.find('[data-test-subj="externalLinkComponent"]')).toHaveLength( + DEFAULT_NUMBER_OF_LINK + ); + }); + + test('it renders correct number of tooltips by default', () => { + const wrapper = mountWithIntl(); + expect(wrapper.find('[data-test-subj="externalLinkTooltip"]')).toHaveLength( + DEFAULT_NUMBER_OF_LINK + ); + }); + + test('it renders correct number of visible link', () => { + (useUiSetting$ as jest.Mock).mockReset(); + (useUiSetting$ as jest.Mock).mockReturnValue([mockCustomizedReputationLinks]); + + const wrapper = mountWithIntl( + + ); + expect(wrapper.find('[data-test-subj="externalLinkComponent"]')).toHaveLength(1); + }); + + test('it renders correct number of tooltips for visible links', () => { + (useUiSetting$ as jest.Mock).mockReset(); + (useUiSetting$ as jest.Mock).mockReturnValue([mockCustomizedReputationLinks]); + + const wrapper = mountWithIntl( + + ); + expect(wrapper.find('[data-test-subj="externalLinkTooltip"]')).toHaveLength(1); + }); }); - test("it encodes ", () => { - const wrapper = mountWithIntl( - alert('XSS')"}>{'Example Link'} - ); - expect(wrapper.find('a').prop('href')).toEqual( - "https://www.virustotal.com/#/search/%3Cscript%3Ealert('XSS')%3C%2Fscript%3E" - ); + describe('invalid customized links', () => { + const mockInvalidLinksEmptyObj = [{}]; + const mockInvalidLinksNoName = [ + { url_template: 'https://talosintelligence.com/reputation_center/lookup?search={{ip}}' }, + ]; + const mockInvalidLinksNoUrl = [{ name: 'Link 1' }]; + const mockInvalidUrl = [{ name: 'Link 1', url_template: "" }]; + afterEach(() => { + (useUiSetting$ as jest.Mock).mockReset(); + }); + + test('it filters empty object', () => { + (useUiSetting$ as jest.Mock).mockReturnValue([mockInvalidLinksEmptyObj]); + + const wrapper = mountWithIntl( + + ); + expect(wrapper.find('[data-test-subj="externalLink"]')).toHaveLength(0); + }); + + test('it filters object without name property', () => { + (useUiSetting$ as jest.Mock).mockReturnValue([mockInvalidLinksNoName]); + + const wrapper = mountWithIntl( + + ); + expect(wrapper.find('[data-test-subj="externalLink"]')).toHaveLength(0); + }); + + test('it filters object without url_template property', () => { + (useUiSetting$ as jest.Mock).mockReturnValue([mockInvalidLinksNoUrl]); + + const wrapper = mountWithIntl( + + ); + expect(wrapper.find('[data-test-subj="externalLink"]')).toHaveLength(0); + }); + + test('it filters object with invalid url', () => { + (useUiSetting$ as jest.Mock).mockReturnValue([mockInvalidUrl]); + + const wrapper = mountWithIntl( + + ); + expect(wrapper.find('[data-test-subj="externalLink"]')).toHaveLength(0); + }); + }); + + describe('external icon', () => { + beforeAll(() => { + (useUiSetting$ as jest.Mock).mockReset(); + (useUiSetting$ as jest.Mock).mockReturnValue([mockCustomizedReputationLinks]); + }); + + afterEach(() => { + (useUiSetting$ as jest.Mock).mockClear(); + }); + + test('it renders correct number of external icons by default', () => { + const wrapper = mountWithIntl(); + expect(wrapper.find('[data-test-subj="externalLinkIcon"]')).toHaveLength(5); + }); + + test('it renders correct number of external icons', () => { + const wrapper = mountWithIntl( + + ); + expect(wrapper.find('[data-test-subj="externalLinkIcon"]')).toHaveLength(1); + }); }); }); diff --git a/x-pack/legacy/plugins/siem/public/components/links/index.tsx b/x-pack/legacy/plugins/siem/public/components/links/index.tsx index b6548e3e950ba..04de0b1d5d3bf 100644 --- a/x-pack/legacy/plugins/siem/public/components/links/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/links/index.tsx @@ -4,9 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiLink } from '@elastic/eui'; -import React from 'react'; +import { EuiLink, EuiToolTip, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React, { useMemo } from 'react'; +import { isNil } from 'lodash/fp'; +import styled from 'styled-components'; +import { + DefaultFieldRendererOverflow, + DEFAULT_MORE_MAX_HEIGHT, +} from '../field_renderers/field_renderers'; import { encodeIpv6 } from '../../lib/helpers'; import { getCaseDetailsUrl, @@ -15,6 +21,13 @@ import { getCreateCaseUrl, } from '../link_to'; import { FlowTarget, FlowTargetSourceDest } from '../../graphql/types'; +import { useUiSetting$ } from '../../lib/kibana'; +import { IP_REPUTATION_LINKS_SETTING } from '../../../common/constants'; +import * as i18n from '../page/network/ip_overview/translations'; +import { isUrlInvalid } from '../../pages/detection_engine/rules/components/step_about_rule/helpers'; +import { ExternalLinkIcon } from '../external_link_icon'; + +export const DEFAULT_NUMBER_OF_LINK = 5; // Internal Links const HostDetailsLinkComponent: React.FC<{ children?: React.ReactNode; hostName: string }> = ({ @@ -26,6 +39,39 @@ const HostDetailsLinkComponent: React.FC<{ children?: React.ReactNode; hostName: ); +const whitelistUrlSchemes = ['http://', 'https://']; +export const ExternalLink = React.memo<{ + url: string; + children?: React.ReactNode; + idx?: number; + overflowIndexStart?: number; + allItemsLimit?: number; +}>( + ({ + url, + children, + idx, + overflowIndexStart = DEFAULT_NUMBER_OF_LINK, + allItemsLimit = DEFAULT_NUMBER_OF_LINK, + }) => { + const lastVisibleItemIndex = overflowIndexStart - 1; + const lastItemIndex = allItemsLimit - 1; + const lastIndexToShow = Math.max(0, Math.min(lastVisibleItemIndex, lastItemIndex)); + const inWhitelist = whitelistUrlSchemes.some(scheme => url.indexOf(scheme) === 0); + return url && inWhitelist && !isUrlInvalid(url) && children ? ( + + + {children} + + {!isNil(idx) && idx < lastIndexToShow && } + + + ) : null; + } +); + +ExternalLink.displayName = 'ExternalLink'; + export const HostDetailsLink = React.memo(HostDetailsLinkComponent); const IPDetailsLinkComponent: React.FC<{ @@ -63,9 +109,9 @@ CreateCaseLink.displayName = 'CreateCaseLink'; // External Links export const GoogleLink = React.memo<{ children?: React.ReactNode; link: string }>( ({ children, link }) => ( - + {children ? children : link} - + ) ); @@ -120,39 +166,136 @@ export const CertificateFingerprintLink = React.memo<{ CertificateFingerprintLink.displayName = 'CertificateFingerprintLink'; -export const ReputationLink = React.memo<{ children?: React.ReactNode; domain: string }>( - ({ children, domain }) => ( - - {children ? children : domain} - - ) -); +enum DefaultReputationLink { + 'virustotal.com' = 'virustotal.com', + 'talosIntelligence.com' = 'talosIntelligence.com', +} -ReputationLink.displayName = 'ReputationLink'; +export interface ReputationLinkSetting { + name: string; + url_template: string; +} -export const VirusTotalLink = React.memo<{ children?: React.ReactNode; link: string }>( - ({ children, link }) => ( - - {children ? children : link} - - ) -); +function isDefaultReputationLink(name: string): name is DefaultReputationLink { + return ( + name === DefaultReputationLink['virustotal.com'] || + name === DefaultReputationLink['talosIntelligence.com'] + ); +} +const isReputationLink = ( + rowItem: string | ReputationLinkSetting +): rowItem is ReputationLinkSetting => + (rowItem as ReputationLinkSetting).url_template !== undefined && + (rowItem as ReputationLinkSetting).name !== undefined; + +export const Comma = styled('span')` + margin-right: 5px; + margin-left: 5px; + &::after { + content: ' ,'; + } +`; + +Comma.displayName = 'Comma'; + +const defaultNameMapping: Record = { + [DefaultReputationLink['virustotal.com']]: i18n.VIEW_VIRUS_TOTAL, + [DefaultReputationLink['talosIntelligence.com']]: i18n.VIEW_TALOS_INTELLIGENCE, +}; + +const ReputationLinkComponent: React.FC<{ + overflowIndexStart?: number; + allItemsLimit?: number; + showDomain?: boolean; + domain: string; + direction?: 'row' | 'column'; +}> = ({ + overflowIndexStart = DEFAULT_NUMBER_OF_LINK, + allItemsLimit = DEFAULT_NUMBER_OF_LINK, + showDomain = false, + domain, + direction = 'row', +}) => { + const [ipReputationLinksSetting] = useUiSetting$( + IP_REPUTATION_LINKS_SETTING + ); + + const ipReputationLinks: ReputationLinkSetting[] = useMemo( + () => + ipReputationLinksSetting + ?.slice(0, allItemsLimit) + .filter( + ({ url_template, name }) => + !isNil(url_template) && !isNil(name) && !isUrlInvalid(url_template) + ) + .map(({ name, url_template }: { name: string; url_template: string }) => ({ + name: isDefaultReputationLink(name) ? defaultNameMapping[name] : name, + url_template: url_template.replace(`{{ip}}`, encodeURIComponent(domain)), + })), + [ipReputationLinksSetting, domain, defaultNameMapping, allItemsLimit] + ); + + return ipReputationLinks?.length > 0 ? ( +
+ + + {ipReputationLinks + ?.slice(0, overflowIndexStart) + .map(({ name, url_template: urlTemplate }: ReputationLinkSetting, id) => ( + + <>{showDomain ? domain : name ?? domain} + + ))} + + + + { + return ( + isReputationLink(rowItem) && ( + + <>{rowItem.name ?? domain} + + ) + ); + }} + moreMaxHeight={DEFAULT_MORE_MAX_HEIGHT} + overflowIndexStart={overflowIndexStart} + /> + + +
+ ) : null; +}; + +ReputationLinkComponent.displayName = 'ReputationLinkComponent'; -VirusTotalLink.displayName = 'VirusTotalLink'; +export const ReputationLink = React.memo(ReputationLinkComponent); export const WhoIsLink = React.memo<{ children?: React.ReactNode; domain: string }>( ({ children, domain }) => ( - + {children ? children : domain} - +
) ); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/__snapshots__/zeek_details.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/__snapshots__/zeek_details.test.tsx.snap index 0a60c8facff9c..6b866aeecc831 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/__snapshots__/zeek_details.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/__snapshots__/zeek_details.test.tsx.snap @@ -498,3 +498,3264 @@ exports[`ZeekDetails rendering it renders the default ZeekDetails 1`] = ` timelineId="test" /> `; + +exports[`ZeekDetails rendering it returns zeek.files if the data does contain zeek.files data 1`] = ` +.c3, +.c3::before, +.c3::after { + -webkit-transition: background 150ms ease, color 150ms ease; + transition: background 150ms ease, color 150ms ease; +} + +.c3 { + border-radius: 2px; + padding: 0 4px 0 8px; + position: relative; + z-index: 0 !important; +} + +.c3::before { + background-image: linear-gradient( 135deg, #535966 25%, transparent 25% ), linear-gradient( -135deg, #535966 25%, transparent 25% ), linear-gradient( 135deg, transparent 75%, #535966 75% ), linear-gradient( -135deg, transparent 75%, #535966 75% ); + background-position: 0 0,1px 0,1px -1px,0px 1px; + background-size: 2px 2px; + bottom: 2px; + content: ''; + display: block; + left: 2px; + position: absolute; + top: 2px; + width: 4px; +} + +.c3:hover, +.c3:hover .euiBadge, +.c3:hover .euiBadge__text { + cursor: move; + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; +} + +.event-column-view:hover .c3, +tr:hover .c3 { + background-color: #343741; +} + +.event-column-view:hover .c3::before, +tr:hover .c3::before { + background-image: linear-gradient( 135deg, #98a2b3 25%, transparent 25% ), linear-gradient( -135deg, #98a2b3 25%, transparent 25% ), linear-gradient( 135deg, transparent 75%, #98a2b3 75% ), linear-gradient( -135deg, transparent 75%, #98a2b3 75% ); +} + +.c3:hover, +.c3:focus, +.event-column-view:hover .c3:hover, +.event-column-view:focus .c3:focus, +tr:hover .c3:hover, +tr:hover .c3:focus { + background-color: #1ba9f5; +} + +.c3:hover, +.c3:focus, +.event-column-view:hover .c3:hover, +.event-column-view:focus .c3:focus, +tr:hover .c3:hover, +tr:hover .c3:focus, +.c3:hover a, +.c3:focus a, +.event-column-view:hover .c3:hover a, +.event-column-view:focus .c3:focus a, +tr:hover .c3:hover a, +tr:hover .c3:focus a, +.c3:hover a:hover, +.c3:focus a:hover, +.event-column-view:hover .c3:hover a:hover, +.event-column-view:focus .c3:focus a:hover, +tr:hover .c3:hover a:hover, +tr:hover .c3:focus a:hover { + color: #1d1e24; +} + +.c3:hover::before, +.c3:focus::before, +.event-column-view:hover .c3:hover::before, +.event-column-view:focus .c3:focus::before, +tr:hover .c3:hover::before, +tr:hover .c3:focus::before { + background-image: linear-gradient( 135deg, #1d1e24 25%, transparent 25% ), linear-gradient( -135deg, #1d1e24 25%, transparent 25% ), linear-gradient( 135deg, transparent 75%, #1d1e24 75% ), linear-gradient( -135deg, transparent 75%, #1d1e24 75% ); +} + +.c2 { + display: inline-block; + max-width: 100%; +} + +.c2 [data-rbd-placeholder-context-id] { + display: none !important; +} + +.c4 > span.euiToolTipAnchor { + display: block; +} + +.c8 { + margin: 0 2px; +} + +.c7 { + margin-top: 3px; +} + +.c6 { + margin-right: 10px; +} + +.c1 { + margin-left: 3px; +} + +.c5 { + margin-left: 6px; +} + +.c0 { + margin: 5px 0; +} + + + + + + + + + + + + + + + +
+
+ + +
+ + + +
+ + + +
+ + +
+ + + + + + +
+ + + + + + + + + + + Cu0n232QMyvNtzb75j + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ + + +
+ + + +
+ + +
+ + + + + + +
+ + + + + + + + + + + files + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ + + +
+ + + +
+ + +
+ + + + + + +
+ + + + + + + + + + + sha1: fa5195a... + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ + + +
+ + + +
+ + +
+ + + + + + +
+ + + + + + + + + + + md5: f7653f1... + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + +
+
+ +
+ + + + + + + + +
+
+ +
+
+
+
+
+
+
+
+ +
+ + + + +
+ +
+ + +
+ + +
+ + +
+ + +
+ + + + +
+ + +
+ + +
+ + + +
+ + +
+ +
+ + +
+ + +
+ + + +
+ + +
+ +
+ +
+
+ + + +
+ + + + +
+ +
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ +
+
+ +
+ + +
+ + +
+ +
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/zeek_details.test.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/zeek_details.test.tsx index 7617a01acf1d9..db51ade6df4c5 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/zeek_details.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/zeek_details.test.tsx @@ -113,9 +113,8 @@ describe('ZeekDetails', () => { /> ); - expect(wrapper.text()).toEqual( - 'Cu0n232QMyvNtzb75jfilessha1: fa5195a...md5: f7653f1...fa5195a5dfacc9d1c68d43600f0e0262cad14dde' - ); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.text()).toEqual('Cu0n232QMyvNtzb75jfilessha1: fa5195a...md5: f7653f1...'); }); test('it returns null for text if the data contains no zeek data', () => { diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/zeek_signature.test.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/zeek_signature.test.tsx index c09bd6b7a356d..f199b537f1be0 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/zeek_signature.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/zeek_signature.test.tsx @@ -79,14 +79,9 @@ describe('ZeekSignature', () => { ).toBeFalsy(); }); - test('should render value', () => { - const wrapper = mount(); - expect(wrapper.text()).toEqual('abc'); - }); - - test('should render link with sha', () => { - const wrapper = mount(); - expect(wrapper.find('a').prop('href')).toEqual('https://www.virustotal.com/#/search/abcdefg'); + test('should render', () => { + const wrapper = shallow(); + expect(wrapper.find('[data-test-subj="reputationLinkSha"]').exists()).toBeTruthy(); }); }); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/zeek_signature.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/zeek_signature.tsx index 72f58df5677e4..57e5ff19eb815 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/zeek_signature.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/zeek_signature.tsx @@ -13,7 +13,7 @@ import { Ecs } from '../../../../../graphql/types'; import { DragEffects, DraggableWrapper } from '../../../../drag_and_drop/draggable_wrapper'; import { escapeDataProviderId } from '../../../../drag_and_drop/helpers'; import { ExternalLinkIcon } from '../../../../external_link_icon'; -import { GoogleLink, VirusTotalLink } from '../../../../links'; +import { GoogleLink, ReputationLink } from '../../../../links'; import { Provider } from '../../../../timeline/data_providers/provider'; import { IS_OPERATOR } from '../../../data_providers/data_provider'; @@ -148,8 +148,12 @@ export const TotalVirusLinkSha = React.memo(({ value }) value != null ? (
- {value} - +
) : null diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/helpers.test.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/helpers.test.ts new file mode 100644 index 0000000000000..5eb503f8ba074 --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/helpers.test.ts @@ -0,0 +1,18 @@ +/* + * 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 { isUrlInvalid } from './helpers'; + +describe('helpers', () => { + describe('isUrlInvalid', () => { + test('verifies invalid url', () => { + expect(isUrlInvalid('this is not a url')).toBeTruthy(); + }); + + test('verifies valid url', () => { + expect(isUrlInvalid('https://www.elastic.co/')).toBeFalsy(); + }); + }); +}); From 0764380ffd50b9f07d8e48bbc2ce90d4c0fabb05 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Wed, 26 Feb 2020 09:51:47 -0700 Subject: [PATCH 097/123] [Metrics UI / Logs UI] Remove field filtering in Source API call (#58553) * [Metrics UI / Logs UI] Remove field filtering in Source API call. * Fixing type_check issues --- .../lib/adapters/fields/adapter_types.ts | 3 +- .../fields/framework_fields_adapter.ts | 99 +------------------ .../infra/server/lib/domains/fields_domain.ts | 3 +- 3 files changed, 4 insertions(+), 101 deletions(-) diff --git a/x-pack/plugins/infra/server/lib/adapters/fields/adapter_types.ts b/x-pack/plugins/infra/server/lib/adapters/fields/adapter_types.ts index 3aaa23b378096..a1630281c2f75 100644 --- a/x-pack/plugins/infra/server/lib/adapters/fields/adapter_types.ts +++ b/x-pack/plugins/infra/server/lib/adapters/fields/adapter_types.ts @@ -9,8 +9,7 @@ import { RequestHandlerContext } from 'src/core/server'; export interface FieldsAdapter { getIndexFields( requestContext: RequestHandlerContext, - indices: string, - timefield: string + indices: string ): Promise; } diff --git a/x-pack/plugins/infra/server/lib/adapters/fields/framework_fields_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/fields/framework_fields_adapter.ts index 834c991d5c6a4..8119c06dedaef 100644 --- a/x-pack/plugins/infra/server/lib/adapters/fields/framework_fields_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/fields/framework_fields_adapter.ts @@ -4,28 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { startsWith, uniq, first } from 'lodash'; import { RequestHandlerContext } from 'src/core/server'; -import { InfraDatabaseSearchResponse } from '../framework'; import { KibanaFramework } from '../framework/kibana_framework_adapter'; import { FieldsAdapter, IndexFieldDescriptor } from './adapter_types'; -import { getAllowedListForPrefix } from '../../../../common/ecs_allowed_list'; -import { getAllCompositeData } from '../../../utils/get_all_composite_data'; -import { createAfterKeyHandler } from '../../../utils/create_afterkey_handler'; - -interface Bucket { - key: { dataset: string }; - doc_count: number; -} - -interface DataSetResponse { - datasets: { - buckets: Bucket[]; - after_key: { - dataset: string; - }; - }; -} export class FrameworkFieldsAdapter implements FieldsAdapter { private framework: KibanaFramework; @@ -36,91 +17,15 @@ export class FrameworkFieldsAdapter implements FieldsAdapter { public async getIndexFields( requestContext: RequestHandlerContext, - indices: string, - timefield: string + indices: string ): Promise { const indexPatternsService = this.framework.getIndexPatternsService(requestContext); const response = await indexPatternsService.getFieldsForWildcard({ pattern: indices, }); - const { dataSets, modules } = await this.getDataSetsAndModules( - requestContext, - indices, - timefield - ); - const allowedList = modules.reduce( - (acc, name) => uniq([...acc, ...getAllowedListForPrefix(name)]), - [] as string[] - ); - const dataSetsWithAllowedList = [...allowedList, ...dataSets]; return response.map(field => ({ ...field, - displayable: dataSetsWithAllowedList.some(name => startsWith(field.name, name)), + displayable: true, })); } - - private async getDataSetsAndModules( - requestContext: RequestHandlerContext, - indices: string, - timefield: string - ): Promise<{ dataSets: string[]; modules: string[] }> { - const params = { - index: indices, - allowNoIndices: true, - ignoreUnavailable: true, - body: { - size: 0, - query: { - bool: { - filter: [ - { - range: { - [timefield]: { - gte: 'now-24h', - lte: 'now', - }, - }, - }, - ], - }, - }, - aggs: { - datasets: { - composite: { - sources: [ - { - dataset: { - terms: { - field: 'event.dataset', - }, - }, - }, - ], - }, - }, - }, - }, - }; - - const bucketSelector = (response: InfraDatabaseSearchResponse<{}, DataSetResponse>) => - (response.aggregations && response.aggregations.datasets.buckets) || []; - const handleAfterKey = createAfterKeyHandler( - 'body.aggs.datasets.composite.after', - input => input?.aggregations?.datasets?.after_key - ); - - const buckets = await getAllCompositeData( - this.framework, - requestContext, - params, - bucketSelector, - handleAfterKey - ); - const dataSets = buckets.map(bucket => bucket.key.dataset); - const modules = dataSets.reduce((acc, dataset) => { - const module = first(dataset.split(/\./)); - return module ? uniq([...acc, module]) : acc; - }, [] as string[]); - return { modules, dataSets }; - } } diff --git a/x-pack/plugins/infra/server/lib/domains/fields_domain.ts b/x-pack/plugins/infra/server/lib/domains/fields_domain.ts index a00c76216da4c..d2e151ca2c3f5 100644 --- a/x-pack/plugins/infra/server/lib/domains/fields_domain.ts +++ b/x-pack/plugins/infra/server/lib/domains/fields_domain.ts @@ -31,8 +31,7 @@ export class InfraFieldsDomain { requestContext, `${includeMetricIndices ? configuration.metricAlias : ''},${ includeLogIndices ? configuration.logAlias : '' - }`, - configuration.fields.timestamp + }` ); return fields; From 55fb05c09f34f371478fd9a951ddb48f07c7a458 Mon Sep 17 00:00:00 2001 From: Maryia Lapata Date: Wed, 26 Feb 2020 20:12:23 +0300 Subject: [PATCH 098/123] [NP] Move ui/kbn_top_nav/kbn_top_nav to kibana_legacy (#58221) * Migrate kbn_top_nav.js to kibana_legacy * Wrap TopNavMenu into i18nContext * Move the kbnTopNav directive definition to kibana_legacy and remove ui/kbn_top_nav Co-authored-by: Elastic Machine --- src/core/MIGRATION.md | 2 +- .../kibana/public/dashboard/legacy_imports.ts | 2 -- .../public/dashboard/np_ready/application.ts | 8 ++++--- .../public/discover/get_inner_angular.ts | 6 ++--- .../core_plugins/kibana/public/kibana.js | 1 - .../kibana/public/visualize/legacy_imports.ts | 2 -- .../public/visualize/np_ready/application.ts | 6 +++-- .../core_plugins/timelion/public/app.js | 4 +++- src/legacy/ui/public/kbn_top_nav/index.js | 20 ----------------- .../kibana_legacy/public/angular/index.ts | 2 ++ .../public/angular}/kbn_top_nav.js | 22 +++++++++++-------- src/plugins/navigation/public/plugin.ts | 4 ++-- .../top_nav_menu/create_top_nav_menu.tsx | 13 +++++++++-- .../public/top_nav_menu/top_nav_menu.tsx | 3 +-- .../dashboard_mode/public/dashboard_viewer.js | 1 - .../plugins/graph/public/application.ts | 10 ++++----- .../plugins/graph/public/legacy_imports.ts | 2 -- .../maps/public/angular/map_controller.js | 2 ++ x-pack/legacy/plugins/maps/public/index.ts | 1 - .../public/np_imports/angular/modules.ts | 6 +++-- .../public/np_imports/legacy_imports.ts | 2 -- 21 files changed, 56 insertions(+), 63 deletions(-) delete mode 100644 src/legacy/ui/public/kbn_top_nav/index.js rename src/{legacy/ui/public/kbn_top_nav => plugins/kibana_legacy/public/angular}/kbn_top_nav.js (90%) diff --git a/src/core/MIGRATION.md b/src/core/MIGRATION.md index 6ee432635a947..4dd6bedfa4f0c 100644 --- a/src/core/MIGRATION.md +++ b/src/core/MIGRATION.md @@ -1169,7 +1169,7 @@ import { setup, start } from '../core_plugins/visualizations/public/legacy'; | `import 'ui/filter_bar'` | `import { FilterBar } from '../data/public'` | Directive is deprecated. | | `import 'ui/query_bar'` | `import { QueryStringInput } from '../data/public'` | Directives are deprecated. | | `import 'ui/search_bar'` | `import { SearchBar } from '../data/public'` | Directive is deprecated. | -| `import 'ui/kbn_top_nav'` | `import { TopNavMenu } from '../navigation/public'` | Directive is still available in `ui/kbn_top_nav`. | +| `import 'ui/kbn_top_nav'` | `import { TopNavMenu } from '../navigation/public'` | Directive was moved to `src/plugins/kibana_legacy`. | | `ui/saved_objects/components/saved_object_finder` | `import { SavedObjectFinder } from '../saved_objects/public'` | | | `core_plugins/interpreter` | `data.expressions` | still in progress | | `ui/courier` | `data.search` | still in progress | diff --git a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts index c1f679e9eb7ac..beadcda595288 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts @@ -28,8 +28,6 @@ export { npSetup, npStart } from 'ui/new_platform'; export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; export { KbnUrl } from 'ui/url/kbn_url'; // @ts-ignore -export { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav'; -// @ts-ignore export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url/index'; export { IInjector } from 'ui/chrome'; export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url'; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts index 7239d8f2258a7..257ba8a4711b0 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts @@ -31,8 +31,6 @@ import { import { Storage } from '../../../../../../plugins/kibana_utils/public'; import { configureAppAngularModule, - createTopNavDirective, - createTopNavHelper, IPrivate, KbnUrlProvider, PrivateProvider, @@ -45,7 +43,11 @@ import { IEmbeddableStart } from '../../../../../../plugins/embeddable/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../../plugins/navigation/public'; import { DataPublicPluginStart } from '../../../../../../plugins/data/public'; import { SharePluginStart } from '../../../../../../plugins/share/public'; -import { KibanaLegacyStart } from '../../../../../../plugins/kibana_legacy/public'; +import { + KibanaLegacyStart, + createTopNavDirective, + createTopNavHelper, +} from '../../../../../../plugins/kibana_legacy/public'; import { SavedObjectLoader } from '../../../../../../plugins/saved_objects/public'; export interface RenderDeps { diff --git a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts index 373395c86636c..bae938d1fb61e 100644 --- a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts +++ b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts @@ -37,8 +37,6 @@ import { GlobalStateProvider } from 'ui/state_management/global_state'; import { StateManagementConfigProvider } from 'ui/state_management/config_provider'; // @ts-ignore import { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url'; -// @ts-ignore -import { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav'; import { DataPublicPluginStart } from '../../../../../plugins/data/public'; import { Storage } from '../../../../../plugins/kibana_utils/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; @@ -63,7 +61,6 @@ import { createFieldChooserDirective } from './np_ready/components/field_chooser import { createDiscoverFieldDirective } from './np_ready/components/field_chooser/discover_field'; import { CollapsibleSidebarProvider } from './np_ready/angular/directives/collapsible_sidebar/collapsible_sidebar'; import { DiscoverStartPlugins } from './plugin'; -import { initAngularBootstrap } from '../../../../../plugins/kibana_legacy/public'; import { createCssTruncateDirective } from './np_ready/angular/directives/css_truncate'; // @ts-ignore import { FixedScrollProvider } from './np_ready/angular/directives/fixed_scroll'; @@ -71,6 +68,7 @@ import { FixedScrollProvider } from './np_ready/angular/directives/fixed_scroll' import { DebounceProviderTimeout } from './np_ready/angular/directives/debounce/debounce'; import { createRenderCompleteDirective } from './np_ready/angular/directives/render_complete'; import { + initAngularBootstrap, configureAppAngularModule, IPrivate, KbnAccessibleClickProvider, @@ -78,6 +76,8 @@ import { PromiseServiceCreator, registerListenEventListener, watchMultiDecorator, + createTopNavDirective, + createTopNavHelper, } from '../../../../../plugins/kibana_legacy/public'; /** diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js index 384c6bd80ec33..a83d1176a7197 100644 --- a/src/legacy/core_plugins/kibana/public/kibana.js +++ b/src/legacy/core_plugins/kibana/public/kibana.js @@ -44,7 +44,6 @@ import 'uiExports/shareContextMenuExtensions'; import 'uiExports/interpreter'; import 'ui/autoload/all'; -import 'ui/kbn_top_nav'; import './home'; import './discover/legacy'; import './visualize/legacy'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts index d9565938c838d..d52d31c2dd79e 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts @@ -34,8 +34,6 @@ export { PersistedState } from 'ui/persisted_state'; export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; // @ts-ignore export { EventsProvider } from 'ui/events'; -// @ts-ignore -export { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav'; export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router'; // @ts-ignore export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts b/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts index 6a8d9ce106f9d..0e1abff4b46f2 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts @@ -23,8 +23,6 @@ import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import { AppMountContext } from 'kibana/public'; import { configureAppAngularModule, - createTopNavDirective, - createTopNavHelper, EventsProvider, GlobalStateProvider, KbnUrlProvider, @@ -36,6 +34,10 @@ import { StateManagementConfigProvider, } from '../legacy_imports'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../../plugins/navigation/public'; +import { + createTopNavDirective, + createTopNavHelper, +} from '../../../../../../plugins/kibana_legacy/public'; // @ts-ignore import { initVisualizeApp } from './legacy_app'; diff --git a/src/legacy/core_plugins/timelion/public/app.js b/src/legacy/core_plugins/timelion/public/app.js index ff8f75c23435e..e4a48c09db832 100644 --- a/src/legacy/core_plugins/timelion/public/app.js +++ b/src/legacy/core_plugins/timelion/public/app.js @@ -37,7 +37,6 @@ require('ui/autoload/all'); import 'ui/directives/input_focus'; import './directives/saved_object_finder'; import 'ui/directives/listen'; -import 'ui/kbn_top_nav'; import './directives/saved_object_save_as_checkbox'; import '../../data/public/legacy'; import './services/saved_sheet_register'; @@ -45,6 +44,9 @@ import './services/saved_sheet_register'; import rootTemplate from 'plugins/timelion/index.html'; import { createSavedVisLoader, TypesService } from '../../visualizations/public'; +import { loadKbnTopNavDirectives } from '../../../../plugins/kibana_legacy/public'; +loadKbnTopNavDirectives(npStart.plugins.navigation.ui); + require('plugins/timelion/directives/cells/cells'); require('plugins/timelion/directives/fixed_element'); require('plugins/timelion/directives/fullscreen/fullscreen'); diff --git a/src/legacy/ui/public/kbn_top_nav/index.js b/src/legacy/ui/public/kbn_top_nav/index.js deleted file mode 100644 index 8a93972c4b226..0000000000000 --- a/src/legacy/ui/public/kbn_top_nav/index.js +++ /dev/null @@ -1,20 +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 './kbn_top_nav'; diff --git a/src/plugins/kibana_legacy/public/angular/index.ts b/src/plugins/kibana_legacy/public/angular/index.ts index 0e18869f1c08b..0b234b7042850 100644 --- a/src/plugins/kibana_legacy/public/angular/index.ts +++ b/src/plugins/kibana_legacy/public/angular/index.ts @@ -22,3 +22,5 @@ export { PromiseServiceCreator } from './promises'; export { watchMultiDecorator } from './watch_multi'; export * from './angular_config'; export { ensureDefaultIndexPattern } from './ensure_default_index_pattern'; +// @ts-ignore +export { createTopNavDirective, createTopNavHelper, loadKbnTopNavDirectives } from './kbn_top_nav'; diff --git a/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js b/src/plugins/kibana_legacy/public/angular/kbn_top_nav.js similarity index 90% rename from src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js rename to src/plugins/kibana_legacy/public/angular/kbn_top_nav.js index 12c3ca2acc3cd..b0ccb4dbc2375 100644 --- a/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js +++ b/src/plugins/kibana_legacy/public/angular/kbn_top_nav.js @@ -17,12 +17,8 @@ * under the License. */ +import angular from 'angular'; import 'ngreact'; -import { wrapInI18nContext } from 'ui/i18n'; -import { uiModules } from 'ui/modules'; -import { npStart } from 'ui/new_platform'; - -const module = uiModules.get('kibana'); export function createTopNavDirective() { return { @@ -75,10 +71,8 @@ export function createTopNavDirective() { }; } -module.directive('kbnTopNav', createTopNavDirective); - export const createTopNavHelper = ({ TopNavMenu }) => reactDirective => { - return reactDirective(wrapInI18nContext(TopNavMenu), [ + return reactDirective(TopNavMenu, [ ['config', { watchDepth: 'value' }], ['disabledButtons', { watchDepth: 'reference' }], @@ -121,4 +115,14 @@ export const createTopNavHelper = ({ TopNavMenu }) => reactDirective => { ]); }; -module.directive('kbnTopNavHelper', createTopNavHelper(npStart.plugins.navigation.ui)); +let isLoaded = false; + +export function loadKbnTopNavDirectives(navUi) { + if (!isLoaded) { + isLoaded = true; + angular + .module('kibana') + .directive('kbnTopNav', createTopNavDirective) + .directive('kbnTopNavHelper', createTopNavHelper(navUi)); + } +} diff --git a/src/plugins/navigation/public/plugin.ts b/src/plugins/navigation/public/plugin.ts index e8df5bcd616d9..5b30ff4913a40 100644 --- a/src/plugins/navigation/public/plugin.ts +++ b/src/plugins/navigation/public/plugin.ts @@ -40,14 +40,14 @@ export class NavigationPublicPlugin } public start( - core: CoreStart, + { i18n }: CoreStart, { data }: NavigationPluginStartDependencies ): NavigationPublicPluginStart { const extensions = this.topNavMenuExtensionsRegistry.getAll(); return { ui: { - TopNavMenu: createTopNav(data, extensions), + TopNavMenu: createTopNav(data, extensions, i18n), }, }; } diff --git a/src/plugins/navigation/public/top_nav_menu/create_top_nav_menu.tsx b/src/plugins/navigation/public/top_nav_menu/create_top_nav_menu.tsx index a78c48b675911..79201a9da88c5 100644 --- a/src/plugins/navigation/public/top_nav_menu/create_top_nav_menu.tsx +++ b/src/plugins/navigation/public/top_nav_menu/create_top_nav_menu.tsx @@ -18,17 +18,26 @@ */ import React from 'react'; +import { I18nStart } from 'kibana/public'; import { DataPublicPluginStart } from 'src/plugins/data/public'; import { TopNavMenuProps, TopNavMenu } from './top_nav_menu'; import { RegisteredTopNavMenuData } from './top_nav_menu_data'; -export function createTopNav(data: DataPublicPluginStart, extraConfig: RegisteredTopNavMenuData[]) { +export function createTopNav( + data: DataPublicPluginStart, + extraConfig: RegisteredTopNavMenuData[], + i18n: I18nStart +) { return (props: TopNavMenuProps) => { const relevantConfig = extraConfig.filter( dataItem => dataItem.appName === undefined || dataItem.appName === props.appName ); const config = (props.config || []).concat(relevantConfig); - return ; + return ( + + + + ); }; } diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx index cf39c82eff3ce..80d1a53cd417f 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx @@ -20,7 +20,6 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { I18nProvider } from '@kbn/i18n/react'; import { TopNavMenuData } from './top_nav_menu_data'; import { TopNavMenuItem } from './top_nav_menu_item'; @@ -78,7 +77,7 @@ export function TopNavMenu(props: TopNavMenuProps) { ); } - return {renderLayout()}; + return renderLayout(); } TopNavMenu.defaultProps = { diff --git a/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js b/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js index e0e49fe59daf4..e76a204a6f27d 100644 --- a/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js +++ b/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js @@ -29,7 +29,6 @@ import 'uiExports/search'; import 'uiExports/shareContextMenuExtensions'; import _ from 'lodash'; import 'ui/autoload/all'; -import 'ui/kbn_top_nav'; import 'ui/agg_response'; import 'ui/agg_types'; import 'leaflet'; diff --git a/x-pack/legacy/plugins/graph/public/application.ts b/x-pack/legacy/plugins/graph/public/application.ts index 7bd18f841b478..536382e62d473 100644 --- a/x-pack/legacy/plugins/graph/public/application.ts +++ b/x-pack/legacy/plugins/graph/public/application.ts @@ -20,11 +20,7 @@ import { IUiSettingsClient, OverlayStart, } from 'kibana/public'; -import { - configureAppAngularModule, - createTopNavDirective, - createTopNavHelper, -} from './legacy_imports'; +import { configureAppAngularModule } from './legacy_imports'; // @ts-ignore import { initGraphApp } from './app'; import { @@ -36,6 +32,10 @@ import { checkLicense } from '../../../../plugins/graph/common/check_license'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../src/plugins/navigation/public'; import { createSavedWorkspacesLoader } from './services/persistence/saved_workspace_loader'; import { Storage } from '../../../../../src/plugins/kibana_utils/public'; +import { + createTopNavDirective, + createTopNavHelper, +} from '../../../../../src/plugins/kibana_legacy/public'; import { addAppRedirectMessageToUrl } from '../../../../../src/plugins/kibana_legacy/public'; /** diff --git a/x-pack/legacy/plugins/graph/public/legacy_imports.ts b/x-pack/legacy/plugins/graph/public/legacy_imports.ts index 84fafdb580abe..274cdc65232e2 100644 --- a/x-pack/legacy/plugins/graph/public/legacy_imports.ts +++ b/x-pack/legacy/plugins/graph/public/legacy_imports.ts @@ -6,6 +6,4 @@ import 'ace'; -// @ts-ignore -export { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav'; export { configureAppAngularModule } from '../../../../../src/plugins/kibana_legacy/public'; diff --git a/x-pack/legacy/plugins/maps/public/angular/map_controller.js b/x-pack/legacy/plugins/maps/public/angular/map_controller.js index c90560a4fcfdf..95c8ff975b1d6 100644 --- a/x-pack/legacy/plugins/maps/public/angular/map_controller.js +++ b/x-pack/legacy/plugins/maps/public/angular/map_controller.js @@ -57,6 +57,8 @@ import { SavedObjectSaveModal, showSaveModal, } from '../../../../../../src/plugins/saved_objects/public'; +import { loadKbnTopNavDirectives } from '../../../../../../src/plugins/kibana_legacy/public'; +loadKbnTopNavDirectives(npStart.plugins.navigation.ui); const savedQueryService = npStart.plugins.data.query.savedQueries; diff --git a/x-pack/legacy/plugins/maps/public/index.ts b/x-pack/legacy/plugins/maps/public/index.ts index 404909c5c51b8..f3213a36bb66d 100644 --- a/x-pack/legacy/plugins/maps/public/index.ts +++ b/x-pack/legacy/plugins/maps/public/index.ts @@ -13,7 +13,6 @@ import 'uiExports/embeddableFactories'; import 'uiExports/embeddableActions'; import 'ui/agg_types'; -import 'ui/kbn_top_nav'; import 'ui/autoload/all'; import 'react-vis/dist/style.css'; diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts index 2acb6031c6773..09ac0f95a1dd9 100644 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts +++ b/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts @@ -9,6 +9,10 @@ import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import { AppMountContext } from 'kibana/public'; import { Storage } from '../../../../../../../src/plugins/kibana_utils/public'; +import { + createTopNavDirective, + createTopNavHelper, +} from '../../../../../../../src/plugins/kibana_legacy/public'; import { GlobalStateProvider, @@ -16,8 +20,6 @@ import { AppStateProvider, EventsProvider, PersistedState, - createTopNavDirective, - createTopNavHelper, KbnUrlProvider, RedirectWhenMissingProvider, npStart, diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/legacy_imports.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/legacy_imports.ts index 012cbc77ce9c8..ea29ac95eb03f 100644 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/legacy_imports.ts +++ b/x-pack/legacy/plugins/monitoring/public/np_imports/legacy_imports.ts @@ -19,7 +19,5 @@ export { AppStateProvider } from 'ui/state_management/app_state'; export { EventsProvider } from 'ui/events'; export { PersistedState } from 'ui/persisted_state'; // @ts-ignore -export { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav'; -// @ts-ignore export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url'; export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router'; From 8511fe378018156b86b651435c9f8eb36b25ac2c Mon Sep 17 00:00:00 2001 From: Michail Yasonik Date: Wed, 26 Feb 2020 12:17:00 -0500 Subject: [PATCH 099/123] Fixing Newsfeed Cloud test bug (#58566) --- test/functional/apps/home/_newsfeed.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/test/functional/apps/home/_newsfeed.ts b/test/functional/apps/home/_newsfeed.ts index 35d7ac8adefa5..096e237850c72 100644 --- a/test/functional/apps/home/_newsfeed.ts +++ b/test/functional/apps/home/_newsfeed.ts @@ -47,10 +47,17 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { it('shows all news from newsfeed', async () => { const objects = await PageObjects.newsfeed.getNewsfeedList(); - expect(objects).to.eql([ - '21 June 2019\nYou are functionally testing the newsfeed widget with fixtures!\nSee test/common/fixtures/plugins/newsfeed/newsfeed_simulation\nGeneric feed-viewer could go here', - '21 June 2019\nStaging too!\nHello world\nGeneric feed-viewer could go here', - ]); + + if (await PageObjects.common.isOss()) { + expect(objects).to.eql([ + '21 June 2019\nYou are functionally testing the newsfeed widget with fixtures!\nSee test/common/fixtures/plugins/newsfeed/newsfeed_simulation\nGeneric feed-viewer could go here', + '21 June 2019\nStaging too!\nHello world\nGeneric feed-viewer could go here', + ]); + } else { + // can't shim the API in cloud so going to check that at least something is rendered + // to test that the API was called and returned something that could be rendered + expect(objects.length).to.be.above(0); + } }); it('clicking on newsfeed icon should close opened newsfeed', async () => { From fa5400f606d77e0f7c2252961242898b96e9ad7f Mon Sep 17 00:00:00 2001 From: Elizabet Oliveira Date: Wed, 26 Feb 2020 18:20:03 +0000 Subject: [PATCH 100/123] [Maps] Improve Layer Style UI (#58406) * Improving Layer Style UI * Removing unnecessary method * Updating snapshot * Changing width value to make use of sass variable Co-authored-by: Elastic Machine --- .../layer_panel/_index.scss | 3 +- .../style_settings/_style_settings.scss | 3 + .../style_settings/style_settings.js | 2 +- .../vector/components/color/_color_stops.scss | 21 ------ .../components/color/color_map_select.js | 1 + .../vector/components/color/color_stops.js | 64 ++++++++++--------- .../components/color/dynamic_color_form.js | 6 +- .../components/color/static_color_form.js | 6 +- .../components/label/dynamic_label_form.js | 6 +- .../components/label/static_label_form.js | 6 +- .../orientation/dynamic_orientation_form.js | 6 +- .../orientation/static_orientation_form.js | 6 +- .../components/size/dynamic_size_form.js | 6 +- .../components/size/static_size_form.js | 6 +- .../vector/components/style_prop_editor.js | 6 +- .../__snapshots__/icon_select.test.js.snap | 2 +- .../components/symbol/dynamic_icon_form.js | 6 +- .../vector/components/symbol/icon_select.js | 1 + .../components/symbol/static_icon_form.js | 6 +- 19 files changed, 88 insertions(+), 75 deletions(-) create mode 100644 x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/_style_settings.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/_index.scss b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/_index.scss index b219f59476ce9..fd074edf032fa 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/_index.scss +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/_index.scss @@ -1,3 +1,4 @@ @import './layer_panel'; @import './filter_editor/filter_editor'; -@import './join_editor/resources/join'; \ No newline at end of file +@import './join_editor/resources/join'; +@import './style_settings/style_settings'; \ No newline at end of file diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/_style_settings.scss b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/_style_settings.scss new file mode 100644 index 0000000000000..249b6dfca5c76 --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/_style_settings.scss @@ -0,0 +1,3 @@ +.mapStyleSettings__fixedBox { + width: $euiSize * 7.5; +} \ No newline at end of file diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/style_settings.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/style_settings.js index 2857065f04c70..69cf51fb29c0d 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/style_settings.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/style_settings.js @@ -21,7 +21,7 @@ export function StyleSettings({ layer, updateStyleDescriptor }) { return ( - + diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/_color_stops.scss b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/_color_stops.scss index 001ca0685d0e9..519e97f4b30cd 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/_color_stops.scss +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/_color_stops.scss @@ -1,6 +1,5 @@ .mapColorStop { position: relative; - padding-right: $euiSizeXL + $euiSizeS; & + & { margin-top: $euiSizeS; @@ -17,23 +16,3 @@ } } -.mapColorStop__icons { - flex-shrink: 0; - display: none; - position: absolute; - right: 0; - top: 50%; - margin-right: -$euiSizeS; - margin-top: -$euiSizeM; -} - -@keyframes mapColorStopBecomeVisible { - - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/color_map_select.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/color_map_select.js index e8d5754ef4206..436a92b619909 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/color_map_select.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/color_map_select.js @@ -105,6 +105,7 @@ export class ColorMapSelect extends Component { onChange={this._onColorMapSelect} valueOfSelected={valueOfSelected} hasDividers={true} + compressed /> {this._renderColorStopsInput()} diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/color_stops.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/color_stops.js index 47c2d037e0c79..3e9b9e2aafc47 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/color_stops.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/color_stops.js @@ -10,7 +10,19 @@ import { removeRow, isColorInvalid } from './color_stops_utils'; import { i18n } from '@kbn/i18n'; import { EuiButtonIcon, EuiColorPicker, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui'; -function getColorStopRow({ index, errors, stopInput, colorInput, deleteButton, onAdd }) { +function getColorStopRow({ index, errors, stopInput, onColorChange, color, deleteButton, onAdd }) { + const colorPickerButtons = ( +
+ {deleteButton} + +
+ ); return ( -
- - {stopInput} - {colorInput} - -
- {deleteButton} - + + {stopInput} + + + -
-
+ +
); } @@ -80,17 +89,6 @@ export const ColorStops = ({ }; } - function getColorInput(onColorChange, color) { - return { - colorError: isColorInvalid(color) - ? i18n.translate('xpack.maps.styles.colorStops.hexWarningLabel', { - defaultMessage: 'Color must provide a valid hex value', - }) - : undefined, - colorInput: , - }; - } - const rows = colorStops.map((colorStop, index) => { const onColorChange = color => { const newColorStops = _.cloneDeep(colorStops); @@ -102,7 +100,15 @@ export const ColorStops = ({ }; const { stopError, stopInput } = getStopInput(colorStop.stop, index); - const { colorError, colorInput } = getColorInput(onColorChange, colorStop.color); + + const color = colorStop.color; + + const colorError = isColorInvalid(color) + ? i18n.translate('xpack.maps.styles.colorStops.hexWarningLabel', { + defaultMessage: 'Color must provide a valid hex value', + }) + : undefined; + const errors = []; if (stopError) { errors.push(stopError); @@ -131,7 +137,7 @@ export const ColorStops = ({ deleteButton = getDeleteButton(onRemove); } - return getColorStopRow({ index, errors, stopInput, colorInput, deleteButton, onAdd }); + return getColorStopRow({ index, errors, stopInput, onColorChange, color, deleteButton, onAdd }); }); return
{rows}
; diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/dynamic_color_form.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/dynamic_color_form.js index af5e5b37f5467..3dc356c31cf30 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/dynamic_color_form.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/color/dynamic_color_form.js @@ -90,8 +90,10 @@ export function DynamicColorForm({ return ( - - {staticDynamicSelect} + + + {staticDynamicSelect} + - {staticDynamicSelect} + + + {staticDynamicSelect} + - {staticDynamicSelect} + + + {staticDynamicSelect} + - {staticDynamicSelect} + + + {staticDynamicSelect} + - {staticDynamicSelect} + + + {staticDynamicSelect} + - {staticDynamicSelect} + + + {staticDynamicSelect} + - - {staticDynamicSelect} + + + {staticDynamicSelect} + - {staticDynamicSelect} + + + {staticDynamicSelect} + - - {staticDynamicSelect} + + + {staticDynamicSelect} + diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/symbol/__snapshots__/icon_select.test.js.snap b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/symbol/__snapshots__/icon_select.test.js.snap index 706dc0763b7ca..8fa69e1a5b467 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/symbol/__snapshots__/icon_select.test.js.snap +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/symbol/__snapshots__/icon_select.test.js.snap @@ -34,7 +34,7 @@ exports[`Should render icon select 1`] = ` } closePopover={[Function]} - display="inlineBlock" + display="block" hasArrow={true} isOpen={false} ownFocus={true} diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/symbol/dynamic_icon_form.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/symbol/dynamic_icon_form.js index afa11daf45217..9065102dc8bd7 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/symbol/dynamic_icon_form.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/symbol/dynamic_icon_form.js @@ -53,8 +53,10 @@ export function DynamicIconForm({ return ( - - {staticDynamicSelect} + + + {staticDynamicSelect} + {this._renderIconSelectable()} diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/symbol/static_icon_form.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/symbol/static_icon_form.js index b20d8f2eba162..9b00b2fe38d7b 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/symbol/static_icon_form.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/symbol/static_icon_form.js @@ -20,8 +20,10 @@ export function StaticIconForm({ }; return ( - - {staticDynamicSelect} + + + {staticDynamicSelect} + Date: Wed, 26 Feb 2020 19:00:54 +0000 Subject: [PATCH 101/123] Migrate existing Cypress tests to Cypress + Cucumber (#57299) * chore: move gitignore to the cypress directory * chore: ignore more test files * fix: do not check the Loading Message It seems not relevant to the main purpose of these tests * chore: use cypres + webpack + cucumber scaffolding See https://github.com/TheBrainFamily/cypress-cucumber-webpack-typescript-example * chore: add eslint and prettier for code linting * feat: convert existing Cypress test into BDD style * feat: add support for using proper Node version in MacOSX * chore: use tslint * chore: use old layout We are keeping cypress as rootDir to follow project's structure. On the other hand, having a second cypress directory at the 2nd level is the default structure, as shown in the examples: - https://github.com/TheBrainFamily/cypress-cucumber-webpack-typescript-example - https://github.com/cypress-io/cypress-example-recipes/tree/a240054d7f5626ffcd7bd668dded96d219c4a7eb/examples/preprocessors__typescript-webpack * chore: remove prelint script meanwhile we fix TS lint * chore: move test results to a specific directory * chore: rename variable following old code * chore: remove non-needed lints, as we are going to use kibana build * chore: import snapshot function from cypress * chore: add readFile utils back from a bad removal * chore: change format of JSON spec file It was automatically changed by tests * chore: move CI directory to the proper layout in order for Jenkins to work * chore: store test-results from proper dir on Jenkins * chore: store artifacts properly on Jenkins * Fix type issues * chore: rename test application to e2e (end-to-end) We are keeping the build system within the test application, isolating dependencies * docs: reorganise docs for APM UI e2e tests * fix: Use proper cypress support file * chore: use existing NPM script for running cypress on CI * chore: update paths in CI scripts * docs: document how the CI runs the tests * chore: use Node 10 for tests * chore: Use kibana's Node version for tests * chore: run yarn install * docs: update docs * fix: path was wrong * docs: fix paths and flags used to load data * docs: elasticsearch fix flag * docs: Bootstrap kibana before running it * docs: remove outdated info * chore: move background steps to the scenario This would avoid not reading the background when the number of scenarios grows Co-authored-by: Dario Gieselaar Co-authored-by: Elastic Machine --- .ci/end2end.groovy | 8 +- .eslintignore | 2 +- src/cli/cluster/cluster_manager.ts | 2 +- src/dev/ci_setup/setup_env.sh | 2 +- src/dev/run_check_lockfile_symlinks.js | 2 +- src/dev/typescript/projects.ts | 2 +- x-pack/legacy/plugins/apm/cypress/README.md | 63 - .../legacy/plugins/apm/cypress/cypress.json | 18 - .../apm/cypress/integration/apm.spec.ts | 53 - .../apm/cypress/screenshots/.gitignore | 1 - .../legacy/plugins/apm/cypress/snapshots.js | 3 - .../plugins/apm/cypress/support/index.ts | 10 - x-pack/legacy/plugins/apm/e2e/.gitignore | 4 + x-pack/legacy/plugins/apm/e2e/README.md | 68 + .../apm/{cypress => e2e}/ci/Dockerfile | 3 +- .../apm/{cypress => e2e}/ci/entrypoint.sh | 6 +- .../apm/{cypress => e2e}/ci/kibana.dev.yml | 0 .../apm/{cypress => e2e}/ci/prepare-kibana.sh | 2 +- x-pack/legacy/plugins/apm/e2e/cypress.json | 19 + .../{ => e2e}/cypress/fixtures/example.json | 0 .../{ => e2e}/cypress/ingest-data/replay.js | 0 .../apm/e2e/cypress/integration/apm.feature | 7 + .../{ => e2e}/cypress/integration/helpers.ts | 0 .../cypress/integration/snapshots.js | 9 +- .../apm/{ => e2e}/cypress/plugins/index.js | 16 +- .../apm/e2e/cypress/support/commands.js | 31 + .../plugins/apm/e2e/cypress/support/index.ts | 27 + .../cypress/support/step_definitions/apm.ts | 45 + .../cypress/typings/index.d.ts} | 0 .../plugins/apm/e2e/cypress/webpack.config.js | 41 + .../plugins/apm/{cypress => e2e}/package.json | 7 +- .../apm/{cypress => e2e}/tsconfig.json | 9 +- .../plugins/apm/{cypress => e2e}/yarn.lock | 2759 ++++++++++++----- x-pack/tsconfig.json | 2 +- 34 files changed, 2302 insertions(+), 919 deletions(-) delete mode 100644 x-pack/legacy/plugins/apm/cypress/README.md delete mode 100644 x-pack/legacy/plugins/apm/cypress/cypress.json delete mode 100644 x-pack/legacy/plugins/apm/cypress/integration/apm.spec.ts delete mode 100644 x-pack/legacy/plugins/apm/cypress/screenshots/.gitignore delete mode 100644 x-pack/legacy/plugins/apm/cypress/snapshots.js delete mode 100644 x-pack/legacy/plugins/apm/cypress/support/index.ts create mode 100644 x-pack/legacy/plugins/apm/e2e/.gitignore create mode 100644 x-pack/legacy/plugins/apm/e2e/README.md rename x-pack/legacy/plugins/apm/{cypress => e2e}/ci/Dockerfile (92%) rename x-pack/legacy/plugins/apm/{cypress => e2e}/ci/entrypoint.sh (87%) rename x-pack/legacy/plugins/apm/{cypress => e2e}/ci/kibana.dev.yml (100%) rename x-pack/legacy/plugins/apm/{cypress => e2e}/ci/prepare-kibana.sh (95%) create mode 100644 x-pack/legacy/plugins/apm/e2e/cypress.json rename x-pack/legacy/plugins/apm/{ => e2e}/cypress/fixtures/example.json (100%) rename x-pack/legacy/plugins/apm/{ => e2e}/cypress/ingest-data/replay.js (100%) create mode 100644 x-pack/legacy/plugins/apm/e2e/cypress/integration/apm.feature rename x-pack/legacy/plugins/apm/{ => e2e}/cypress/integration/helpers.ts (100%) rename x-pack/legacy/plugins/apm/{ => e2e}/cypress/integration/snapshots.js (61%) rename x-pack/legacy/plugins/apm/{ => e2e}/cypress/plugins/index.js (79%) create mode 100644 x-pack/legacy/plugins/apm/e2e/cypress/support/commands.js create mode 100644 x-pack/legacy/plugins/apm/e2e/cypress/support/index.ts create mode 100644 x-pack/legacy/plugins/apm/e2e/cypress/support/step_definitions/apm.ts rename x-pack/legacy/plugins/apm/{cypress/cypress.d.ts => e2e/cypress/typings/index.d.ts} (100%) create mode 100644 x-pack/legacy/plugins/apm/e2e/cypress/webpack.config.js rename x-pack/legacy/plugins/apm/{cypress => e2e}/package.json (66%) rename x-pack/legacy/plugins/apm/{cypress => e2e}/tsconfig.json (51%) rename x-pack/legacy/plugins/apm/{cypress => e2e}/yarn.lock (61%) diff --git a/.ci/end2end.groovy b/.ci/end2end.groovy index 38fed4aca19dc..8ad810717d86e 100644 --- a/.ci/end2end.groovy +++ b/.ci/end2end.groovy @@ -13,7 +13,7 @@ pipeline { BASE_DIR = 'src/github.com/elastic/kibana' HOME = "${env.WORKSPACE}" APM_ITS = 'apm-integration-testing' - CYPRESS_DIR = 'x-pack/legacy/plugins/apm/cypress' + CYPRESS_DIR = 'x-pack/legacy/plugins/apm/e2e' PIPELINE_LOG_LEVEL = 'DEBUG' } options { @@ -107,7 +107,7 @@ pipeline { dir("${BASE_DIR}"){ sh ''' jobs -l - docker build --tag cypress ${CYPRESS_DIR}/ci + docker build --tag cypress --build-arg NODE_VERSION=$(cat .node-version) ${CYPRESS_DIR}/ci docker run --rm -t --user "$(id -u):$(id -g)" \ -v `pwd`:/app --network="host" \ --name cypress cypress''' @@ -116,8 +116,8 @@ pipeline { post { always { dir("${BASE_DIR}"){ - archiveArtifacts(allowEmptyArchive: false, artifacts: "${CYPRESS_DIR}/screenshots/**,${CYPRESS_DIR}/videos/**,${CYPRESS_DIR}/*e2e-tests.xml") - junit(allowEmptyResults: true, testResults: "${CYPRESS_DIR}/*e2e-tests.xml") + archiveArtifacts(allowEmptyArchive: false, artifacts: "${CYPRESS_DIR}/**/screenshots/**,${CYPRESS_DIR}/**/videos/**,${CYPRESS_DIR}/**/test-results/*e2e-tests.xml") + junit(allowEmptyResults: true, testResults: "${CYPRESS_DIR}/**/test-results/*e2e-tests.xml") } dir("${APM_ITS}"){ sh 'docker-compose logs > apm-its.log || true' diff --git a/.eslintignore b/.eslintignore index c3921bd22e1ab..357d735e8044b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -39,7 +39,7 @@ src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/lib/fixtures/moc /x-pack/legacy/plugins/infra/common/graphql/types.ts /x-pack/legacy/plugins/infra/public/graphql/types.ts /x-pack/legacy/plugins/infra/server/graphql/types.ts -/x-pack/legacy/plugins/apm/cypress/**/snapshots.js +/x-pack/legacy/plugins/apm/e2e/cypress/**/snapshots.js /src/legacy/plugin_discovery/plugin_pack/__tests__/fixtures/plugins/broken **/graphql/types.ts **/*.js.snap diff --git a/src/cli/cluster/cluster_manager.ts b/src/cli/cluster/cluster_manager.ts index 2f308915fb332..8862b96e74401 100644 --- a/src/cli/cluster/cluster_manager.ts +++ b/src/cli/cluster/cluster_manager.ts @@ -264,7 +264,7 @@ export class ClusterManager { fromRoot('src/legacy/server/sass/__tmp__'), fromRoot('x-pack/legacy/plugins/reporting/.chromium'), fromRoot('x-pack/legacy/plugins/siem/cypress'), - fromRoot('x-pack/legacy/plugins/apm/cypress'), + fromRoot('x-pack/legacy/plugins/apm/e2e/cypress'), fromRoot('x-pack/legacy/plugins/apm/scripts'), fromRoot('x-pack/legacy/plugins/canvas/canvas_plugin_src'), // prevents server from restarting twice for Canvas plugin changes, 'plugins/java_languageserver', diff --git a/src/dev/ci_setup/setup_env.sh b/src/dev/ci_setup/setup_env.sh index 823c70e80fe7c..dc3fa38f3129c 100644 --- a/src/dev/ci_setup/setup_env.sh +++ b/src/dev/ci_setup/setup_env.sh @@ -168,4 +168,4 @@ if [[ -d "$ES_DIR" && -f "$ES_JAVA_PROP_PATH" ]]; then export JAVA_HOME=$HOME/.java/$ES_BUILD_JAVA fi -export CI_ENV_SETUP=true +export CI_ENV_SETUP=true \ No newline at end of file diff --git a/src/dev/run_check_lockfile_symlinks.js b/src/dev/run_check_lockfile_symlinks.js index e7fd7e8831405..54a8cdf638a78 100644 --- a/src/dev/run_check_lockfile_symlinks.js +++ b/src/dev/run_check_lockfile_symlinks.js @@ -35,7 +35,7 @@ const IGNORE_FILE_GLOBS = [ // fixtures aren't used in production, ignore them '**/*fixtures*/**/*', // cypress isn't used in production, ignore it - 'x-pack/legacy/plugins/apm/cypress/*', + 'x-pack/legacy/plugins/apm/e2e/*', ]; run(async ({ log }) => { diff --git a/src/dev/typescript/projects.ts b/src/dev/typescript/projects.ts index fb35e5ce526ed..34756912fc247 100644 --- a/src/dev/typescript/projects.ts +++ b/src/dev/typescript/projects.ts @@ -30,7 +30,7 @@ export const PROJECTS = [ new Project(resolve(REPO_ROOT, 'x-pack/legacy/plugins/siem/cypress/tsconfig.json'), { name: 'siem/cypress', }), - new Project(resolve(REPO_ROOT, 'x-pack/legacy/plugins/apm/cypress/tsconfig.json'), { + new Project(resolve(REPO_ROOT, 'x-pack/legacy/plugins/apm/e2e/tsconfig.json'), { name: 'apm/cypress', disableTypeCheck: true, }), diff --git a/x-pack/legacy/plugins/apm/cypress/README.md b/x-pack/legacy/plugins/apm/cypress/README.md deleted file mode 100644 index 7b44e0d9fce28..0000000000000 --- a/x-pack/legacy/plugins/apm/cypress/README.md +++ /dev/null @@ -1,63 +0,0 @@ -### How to run - -_Note: Run the following commands from `kibana/x-pack/legacy/plugins/apm/cypress`._ - -#### Interactive mode - -``` -yarn cypress open -``` - -#### Headless mode - -``` -yarn cypress run -``` - -### Connect to Elasticsearch on Cloud (internal devs only) - -Find the credentials for the cluster [here](https://github.com/elastic/apm-dev/blob/master/docs/credentials/apm-ui-clusters.md#e2e-cluster). The cloud instance contains the static data set - -### Kibana - -#### `--no-base-path` - -Kibana must be started with `yarn start --no-base-path` - -#### Content Security Policy (CSP) Settings - -Your local or cloud Kibana server must have the `csp.strict: false` setting -configured in `kibana.dev.yml`, or `kibana.yml`, as shown in the example below: - -```yaml -csp.strict: false -``` - -The above setting is required to prevent the _Please upgrade -your browser_ / _This Kibana installation has strict security requirements -enabled that your current browser does not meet._ warning that's displayed for -unsupported user agents, like the one reported by Cypress when running tests. - -### Ingest static data into Elasticsearch via APM Server - -1. Download [static data file](https://storage.googleapis.com/apm-ui-e2e-static-data/events.json) - -2. Post to APM Server - -``` -node ingest-data/replay.js --server-url http://localhost:8200 --secret-token abcd --events ./events.json -``` - -### Generate static data - -Capture data from all agents with [apm-integration-testing](https://github.com/elastic/apm-integration-testing): - -``` -./scripts/compose.py start master --all --apm-server-record -``` - -To copy the captured data from the container to the host: - -``` -docker cp localtesting_8.0.0_apm-server-2:/app/events.json . -``` diff --git a/x-pack/legacy/plugins/apm/cypress/cypress.json b/x-pack/legacy/plugins/apm/cypress/cypress.json deleted file mode 100644 index 69852346359fa..0000000000000 --- a/x-pack/legacy/plugins/apm/cypress/cypress.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "baseUrl": "http://localhost:5601", - "video": false, - "trashAssetsBeforeRuns": false, - "fileServerFolder": "../", - "fixturesFolder": "./fixtures", - "integrationFolder": "./integration", - "pluginsFile": "./plugins/index.js", - "screenshotsFolder": "./screenshots", - "supportFile": "./support/index.ts", - "videosFolder": "./videos", - "useRelativeSnapshots": true, - "reporter": "junit", - "reporterOptions": { - "mochaFile": "[hash]-e2e-tests.xml", - "toConsole": false - } -} diff --git a/x-pack/legacy/plugins/apm/cypress/integration/apm.spec.ts b/x-pack/legacy/plugins/apm/cypress/integration/apm.spec.ts deleted file mode 100644 index 3d0ff276fcdd8..0000000000000 --- a/x-pack/legacy/plugins/apm/cypress/integration/apm.spec.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { loginAndWaitForPage } from './helpers'; - -describe('When clicking opbeans-go service', () => { - before(() => { - // open service overview page - loginAndWaitForPage(`/app/apm#/services`); - - // show loading text for services - cy.contains('Loading...'); - - // click opbeans-go service - cy.get(':contains(opbeans-go)') - .last() - .click({ force: true }); - }); - - it('should redirect to correct path with correct params', () => { - cy.url().should('contain', `/app/apm#/services/opbeans-go/transactions`); - cy.url().should('contain', `transactionType=request`); - }); - - describe('transaction duration charts', () => { - it('should have correct y-axis ticks', () => { - const yAxisTick = - '[data-cy=transaction-duration-charts] .rv-xy-plot__axis--vertical .rv-xy-plot__axis__tick__text'; - - cy.get(yAxisTick) - .eq(2) - .invoke('text') - .snapshot(); - - cy.get(yAxisTick) - .eq(1) - .invoke('text') - .snapshot(); - - cy.get(yAxisTick) - .eq(0) - .invoke('text') - .snapshot(); - }); - }); - - describe('TPM charts', () => {}); - - describe('Transaction group list', () => {}); -}); diff --git a/x-pack/legacy/plugins/apm/cypress/screenshots/.gitignore b/x-pack/legacy/plugins/apm/cypress/screenshots/.gitignore deleted file mode 100644 index 72e8ffc0db8aa..0000000000000 --- a/x-pack/legacy/plugins/apm/cypress/screenshots/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/x-pack/legacy/plugins/apm/cypress/snapshots.js b/x-pack/legacy/plugins/apm/cypress/snapshots.js deleted file mode 100644 index 58e58fdaf8684..0000000000000 --- a/x-pack/legacy/plugins/apm/cypress/snapshots.js +++ /dev/null @@ -1,3 +0,0 @@ -// auto-generated by @cypress/snapshot -{ -} diff --git a/x-pack/legacy/plugins/apm/cypress/support/index.ts b/x-pack/legacy/plugins/apm/cypress/support/index.ts deleted file mode 100644 index 08acd31affeda..0000000000000 --- a/x-pack/legacy/plugins/apm/cypress/support/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -// @ts-ignore -import { register } from '@cypress/snapshot'; - -register(); diff --git a/x-pack/legacy/plugins/apm/e2e/.gitignore b/x-pack/legacy/plugins/apm/e2e/.gitignore new file mode 100644 index 0000000000000..10c769065fc28 --- /dev/null +++ b/x-pack/legacy/plugins/apm/e2e/.gitignore @@ -0,0 +1,4 @@ +cypress/ingest-data/events.json +cypress/screenshots/* + +cypress/test-results diff --git a/x-pack/legacy/plugins/apm/e2e/README.md b/x-pack/legacy/plugins/apm/e2e/README.md new file mode 100644 index 0000000000000..73a1e860f5564 --- /dev/null +++ b/x-pack/legacy/plugins/apm/e2e/README.md @@ -0,0 +1,68 @@ +# End-To-End (e2e) Test for APM UI + +## Ingest static data into Elasticsearch via APM Server + +1. Start Elasticsearch and APM Server, using [apm-integration-testing](https://github.com/elastic/apm-integration-testing): + +```shell +$ git clone https://github.com/elastic/apm-integration-testing.git +$ cd apm-integration-testing +./scripts/compose.py start master --no-kibana --no-xpack-secure +``` + +2. Download [static data file](https://storage.googleapis.com/apm-ui-e2e-static-data/events.json) + +```shell +$ cd x-pack/legacy/plugins/apm/e2e/cypress/ingest-data +$ curl https://storage.googleapis.com/apm-ui-e2e-static-data/events.json --output events.json +``` + +3. Post to APM Server + +```shell +$ cd x-pack/legacy/plugins/apm/e2e/cypress/ingest-data +$ node replay.js --server-url http://localhost:8200 --secret-token abcd --events ./events.json +``` +>This process will take a few minutes to ingest all data + +4. Start Kibana + +```shell +$ yarn kbn bootstrap +$ yarn start --no-base-path --csp.strict=false +``` + +> Content Security Policy (CSP) Settings: Your Kibana instance must have the `csp.strict: false`. + +## How to run the tests + +_Note: Run the following commands from `kibana/x-pack/legacy/plugins/apm/e2e/cypress`._ + +### Interactive mode + +``` +yarn cypress open +``` + +### Headless mode + +``` +yarn cypress run +``` + +## Reproducing CI builds + +>This process is very slow compared to the local development described above. Consider that the CI must install and configure the build tools and create a Docker image for the project to run tests in a consistent manner. + +The Jenkins CI uses a shell script to prepare Kibana: + +```shell +# Prepare and run Kibana locally +$ x-pack/legacy/plugins/apm/e2e/ci/prepare-kibana.sh +# Build Docker image for Kibana +$ docker build --tag cypress --build-arg NODE_VERSION=$(cat .node-version) x-pack/legacy/plugins/apm/e2e/ci +# Run Docker image +$ docker run --rm -t --user "$(id -u):$(id -g)" \ + -v `pwd`:/app --network="host" \ + --name cypress cypress +``` diff --git a/x-pack/legacy/plugins/apm/cypress/ci/Dockerfile b/x-pack/legacy/plugins/apm/e2e/ci/Dockerfile similarity index 92% rename from x-pack/legacy/plugins/apm/cypress/ci/Dockerfile rename to x-pack/legacy/plugins/apm/e2e/ci/Dockerfile index e59e1f47da0b9..2bcc5a5fd843a 100644 --- a/x-pack/legacy/plugins/apm/cypress/ci/Dockerfile +++ b/x-pack/legacy/plugins/apm/e2e/ci/Dockerfile @@ -1,4 +1,5 @@ -FROM node:12 +ARG NODE_VERSION +FROM node:$NODE_VERSION RUN apt-get -qq update \ && apt-get -y -qq install xvfb \ diff --git a/x-pack/legacy/plugins/apm/cypress/ci/entrypoint.sh b/x-pack/legacy/plugins/apm/e2e/ci/entrypoint.sh similarity index 87% rename from x-pack/legacy/plugins/apm/cypress/ci/entrypoint.sh rename to x-pack/legacy/plugins/apm/e2e/ci/entrypoint.sh index 1bcddac3b8020..f7226dca1d276 100755 --- a/x-pack/legacy/plugins/apm/cypress/ci/entrypoint.sh +++ b/x-pack/legacy/plugins/apm/e2e/ci/entrypoint.sh @@ -21,9 +21,9 @@ npm config set cache ${HOME} # --exclude=packages/ \ # --exclude=built_assets --exclude=target \ # --exclude=data /app ${HOME}/ -#cd ${HOME}/app/x-pack/legacy/plugins/apm/cypress +#cd ${HOME}/app/x-pack/legacy/plugins/apm/e2e/cypress -cd /app/x-pack/legacy/plugins/apm/cypress +cd /app/x-pack/legacy/plugins/apm/e2e ## Install dependencies for cypress CI=true npm install yarn install @@ -33,4 +33,4 @@ npm install wait-on ./node_modules/.bin/wait-on ${CYPRESS_BASE_URL}/status && echo 'Kibana is up and running' # Run cypress -./node_modules/.bin/cypress run +npm run cypress:run diff --git a/x-pack/legacy/plugins/apm/cypress/ci/kibana.dev.yml b/x-pack/legacy/plugins/apm/e2e/ci/kibana.dev.yml similarity index 100% rename from x-pack/legacy/plugins/apm/cypress/ci/kibana.dev.yml rename to x-pack/legacy/plugins/apm/e2e/ci/kibana.dev.yml diff --git a/x-pack/legacy/plugins/apm/cypress/ci/prepare-kibana.sh b/x-pack/legacy/plugins/apm/e2e/ci/prepare-kibana.sh similarity index 95% rename from x-pack/legacy/plugins/apm/cypress/ci/prepare-kibana.sh rename to x-pack/legacy/plugins/apm/e2e/ci/prepare-kibana.sh index d6fd620195b94..4f176fd0070f5 100755 --- a/x-pack/legacy/plugins/apm/cypress/ci/prepare-kibana.sh +++ b/x-pack/legacy/plugins/apm/e2e/ci/prepare-kibana.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -CYPRESS_DIR="x-pack/legacy/plugins/apm/cypress" +CYPRESS_DIR="x-pack/legacy/plugins/apm/e2e" echo "1/3 Install dependencies ..." # shellcheck disable=SC1091 diff --git a/x-pack/legacy/plugins/apm/e2e/cypress.json b/x-pack/legacy/plugins/apm/e2e/cypress.json new file mode 100644 index 0000000000000..310964656f107 --- /dev/null +++ b/x-pack/legacy/plugins/apm/e2e/cypress.json @@ -0,0 +1,19 @@ +{ + "baseUrl": "http://localhost:5601", + "video": false, + "trashAssetsBeforeRuns": false, + "fileServerFolder": "../", + "fixturesFolder": "./cypress/fixtures", + "integrationFolder": "./cypress/integration", + "pluginsFile": "./cypress/plugins/index.js", + "screenshotsFolder": "./cypress/screenshots", + "supportFile": "./cypress/support/index.ts", + "videosFolder": "./cypress/videos", + "useRelativeSnapshots": true, + "reporter": "junit", + "reporterOptions": { + "mochaFile": "./cypress/test-results/[hash]-e2e-tests.xml", + "toConsole": false + }, + "testFiles": "**/*.{feature,features}" +} diff --git a/x-pack/legacy/plugins/apm/cypress/fixtures/example.json b/x-pack/legacy/plugins/apm/e2e/cypress/fixtures/example.json similarity index 100% rename from x-pack/legacy/plugins/apm/cypress/fixtures/example.json rename to x-pack/legacy/plugins/apm/e2e/cypress/fixtures/example.json diff --git a/x-pack/legacy/plugins/apm/cypress/ingest-data/replay.js b/x-pack/legacy/plugins/apm/e2e/cypress/ingest-data/replay.js similarity index 100% rename from x-pack/legacy/plugins/apm/cypress/ingest-data/replay.js rename to x-pack/legacy/plugins/apm/e2e/cypress/ingest-data/replay.js diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/integration/apm.feature b/x-pack/legacy/plugins/apm/e2e/cypress/integration/apm.feature new file mode 100644 index 0000000000000..01fee2bf68b09 --- /dev/null +++ b/x-pack/legacy/plugins/apm/e2e/cypress/integration/apm.feature @@ -0,0 +1,7 @@ +Feature: APM + + Scenario: Transaction duration charts + Given a user browses the APM UI application + When the user inspects the opbeans-go service + Then should redirect to correct path with correct params + And should have correct y-axis ticks \ No newline at end of file diff --git a/x-pack/legacy/plugins/apm/cypress/integration/helpers.ts b/x-pack/legacy/plugins/apm/e2e/cypress/integration/helpers.ts similarity index 100% rename from x-pack/legacy/plugins/apm/cypress/integration/helpers.ts rename to x-pack/legacy/plugins/apm/e2e/cypress/integration/helpers.ts diff --git a/x-pack/legacy/plugins/apm/cypress/integration/snapshots.js b/x-pack/legacy/plugins/apm/e2e/cypress/integration/snapshots.js similarity index 61% rename from x-pack/legacy/plugins/apm/cypress/integration/snapshots.js rename to x-pack/legacy/plugins/apm/e2e/cypress/integration/snapshots.js index a2ff071645732..0e4b91ab45a40 100644 --- a/x-pack/legacy/plugins/apm/cypress/integration/snapshots.js +++ b/x-pack/legacy/plugins/apm/e2e/cypress/integration/snapshots.js @@ -8,5 +8,12 @@ module.exports = { } } }, - "__version": "3.4.1" + "__version": "3.8.3", + "APM": { + "Transaction duration charts": { + "1": "3.7 min", + "2": "1.8 min", + "3": "0.0 min" + } + } } diff --git a/x-pack/legacy/plugins/apm/cypress/plugins/index.js b/x-pack/legacy/plugins/apm/e2e/cypress/plugins/index.js similarity index 79% rename from x-pack/legacy/plugins/apm/cypress/plugins/index.js rename to x-pack/legacy/plugins/apm/e2e/cypress/plugins/index.js index 4dd55c16d4a0e..15e469f187651 100644 --- a/x-pack/legacy/plugins/apm/cypress/plugins/index.js +++ b/x-pack/legacy/plugins/apm/e2e/cypress/plugins/index.js @@ -22,22 +22,8 @@ const wp = require('@cypress/webpack-preprocessor'); const fs = require('fs'); module.exports = on => { - // add typescript support const options = { - webpackOptions: { - resolve: { - extensions: ['.ts', '.tsx', '.js'] - }, - module: { - rules: [ - { - test: /\.tsx?$/, - loader: 'ts-loader', - options: { transpileOnly: true } - } - ] - } - } + webpackOptions: require('../webpack.config.js') }; on('file:preprocessor', wp(options)); diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/support/commands.js b/x-pack/legacy/plugins/apm/e2e/cypress/support/commands.js new file mode 100644 index 0000000000000..9a2e54b102c5e --- /dev/null +++ b/x-pack/legacy/plugins/apm/e2e/cypress/support/commands.js @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add("login", (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This is will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/support/index.ts b/x-pack/legacy/plugins/apm/e2e/cypress/support/index.ts new file mode 100644 index 0000000000000..8a7a9f64cc461 --- /dev/null +++ b/x-pack/legacy/plugins/apm/e2e/cypress/support/index.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. + */ + +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +import './commands'; + +// @ts-ignore +import { register } from '@cypress/snapshot'; + +register(); diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/support/step_definitions/apm.ts b/x-pack/legacy/plugins/apm/e2e/cypress/support/step_definitions/apm.ts new file mode 100644 index 0000000000000..f2f1e515f967a --- /dev/null +++ b/x-pack/legacy/plugins/apm/e2e/cypress/support/step_definitions/apm.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'; +import { loginAndWaitForPage } from '../../integration/helpers'; + +Given(`a user browses the APM UI application`, () => { + // open service overview page + loginAndWaitForPage(`/app/apm#/services`); +}); + +When(`the user inspects the opbeans-go service`, () => { + // click opbeans-go service + cy.get(':contains(opbeans-go)') + .last() + .click({ force: true }); +}); + +Then(`should redirect to correct path with correct params`, () => { + cy.url().should('contain', `/app/apm#/services/opbeans-go/transactions`); + cy.url().should('contain', `transactionType=request`); +}); + +Then(`should have correct y-axis ticks`, () => { + const yAxisTick = + '[data-cy=transaction-duration-charts] .rv-xy-plot__axis--vertical .rv-xy-plot__axis__tick__text'; + + cy.get(yAxisTick) + .eq(2) + .invoke('text') + .snapshot(); + + cy.get(yAxisTick) + .eq(1) + .invoke('text') + .snapshot(); + + cy.get(yAxisTick) + .eq(0) + .invoke('text') + .snapshot(); +}); diff --git a/x-pack/legacy/plugins/apm/cypress/cypress.d.ts b/x-pack/legacy/plugins/apm/e2e/cypress/typings/index.d.ts similarity index 100% rename from x-pack/legacy/plugins/apm/cypress/cypress.d.ts rename to x-pack/legacy/plugins/apm/e2e/cypress/typings/index.d.ts diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/webpack.config.js b/x-pack/legacy/plugins/apm/e2e/cypress/webpack.config.js new file mode 100644 index 0000000000000..823b23cfdffec --- /dev/null +++ b/x-pack/legacy/plugins/apm/e2e/cypress/webpack.config.js @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +module.exports = { + resolve: { + extensions: ['.ts', '.js'] + }, + node: { fs: 'empty', child_process: 'empty', readline: 'empty' }, + module: { + rules: [ + { + test: /\.ts$/, + exclude: [/node_modules/], + use: [ + { + loader: 'ts-loader' + } + ] + }, + { + test: /\.feature$/, + use: [ + { + loader: 'cypress-cucumber-preprocessor/loader' + } + ] + }, + { + test: /\.features$/, + use: [ + { + loader: 'cypress-cucumber-preprocessor/lib/featuresLoader' + } + ] + } + ] + } +}; diff --git a/x-pack/legacy/plugins/apm/cypress/package.json b/x-pack/legacy/plugins/apm/e2e/package.json similarity index 66% rename from x-pack/legacy/plugins/apm/cypress/package.json rename to x-pack/legacy/plugins/apm/e2e/package.json index 59f76ba250ad7..c9026636e64fb 100644 --- a/x-pack/legacy/plugins/apm/cypress/package.json +++ b/x-pack/legacy/plugins/apm/e2e/package.json @@ -5,17 +5,20 @@ "license": "MIT", "scripts": { "cypress:open": "cypress open", - "cypress:run": "cypress run" + "cypress:run": "cypress run --spec **/*.feature" }, "dependencies": { "@cypress/snapshot": "^2.1.3", "@cypress/webpack-preprocessor": "^4.1.0", + "@types/cypress-cucumber-preprocessor": "^1.14.0", "@types/js-yaml": "^3.12.1", + "@types/node": "^10.12.11", "cypress": "^3.5.0", + "cypress-cucumber-preprocessor": "^2.0.1", "js-yaml": "^3.13.1", "p-limit": "^2.2.1", "ts-loader": "^6.1.0", - "typescript": "3.7.2", + "typescript": "3.7.5", "webpack": "^4.41.5" } } diff --git a/x-pack/legacy/plugins/apm/cypress/tsconfig.json b/x-pack/legacy/plugins/apm/e2e/tsconfig.json similarity index 51% rename from x-pack/legacy/plugins/apm/cypress/tsconfig.json rename to x-pack/legacy/plugins/apm/e2e/tsconfig.json index e57b9c86a8f03..de498816e30a4 100644 --- a/x-pack/legacy/plugins/apm/cypress/tsconfig.json +++ b/x-pack/legacy/plugins/apm/e2e/tsconfig.json @@ -1,8 +1,13 @@ { "extends": "../../../../tsconfig.json", "exclude": [], - "include": ["./**/*"], + "include": [ + "./**/*" + ], "compilerOptions": { - "types": ["cypress", "node"] + "types": [ + "cypress", + "node" + ] } } diff --git a/x-pack/legacy/plugins/apm/cypress/yarn.lock b/x-pack/legacy/plugins/apm/e2e/yarn.lock similarity index 61% rename from x-pack/legacy/plugins/apm/cypress/yarn.lock rename to x-pack/legacy/plugins/apm/e2e/yarn.lock index 4940217fa7ce3..48e6013fb6986 100644 --- a/x-pack/legacy/plugins/apm/cypress/yarn.lock +++ b/x-pack/legacy/plugins/apm/e2e/yarn.lock @@ -2,592 +2,758 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" - integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== dependencies: - "@babel/highlight" "^7.0.0" + "@babel/highlight" "^7.8.3" -"@babel/core@^7.0.1": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.6.0.tgz#9b00f73554edd67bebc86df8303ef678be3d7b48" - integrity sha512-FuRhDRtsd6IptKpHXAa+4WPZYY2ZzgowkbLBecEDDSje1X/apG7jQM33or3NdOmjXBKWGOg4JmSiRfUfuTtHXw== - dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.6.0" - "@babel/helpers" "^7.6.0" - "@babel/parser" "^7.6.0" - "@babel/template" "^7.6.0" - "@babel/traverse" "^7.6.0" - "@babel/types" "^7.6.0" +"@babel/compat-data@^7.8.4": + version "7.8.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.8.5.tgz#d28ce872778c23551cbb9432fc68d28495b613b9" + integrity sha512-jWYUqQX/ObOhG1UiEkbH5SANsE/8oKXiQWjj7p7xgj9Zmnt//aUvyz4dBkK0HNsS8/cbyC5NmmH87VekW+mXFg== + dependencies: + browserslist "^4.8.5" + invariant "^2.2.4" + semver "^5.5.0" + +"@babel/core@7.4.5": + version "7.4.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.5.tgz#081f97e8ffca65a9b4b0fdc7e274e703f000c06a" + integrity sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.4.4" + "@babel/helpers" "^7.4.4" + "@babel/parser" "^7.4.5" + "@babel/template" "^7.4.4" + "@babel/traverse" "^7.4.5" + "@babel/types" "^7.4.4" convert-source-map "^1.1.0" debug "^4.1.0" json5 "^2.1.0" + lodash "^4.17.11" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/core@^7.0.1": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e" + integrity sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.4" + "@babel/helpers" "^7.8.4" + "@babel/parser" "^7.8.4" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.4" + "@babel/types" "^7.8.3" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.0" lodash "^4.17.13" resolve "^1.3.2" semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.6.0.tgz#e2c21efbfd3293ad819a2359b448f002bfdfda56" - integrity sha512-Ms8Mo7YBdMMn1BYuNtKuP/z0TgEIhbcyB8HVR6PPNYp4P61lMsABiS4A3VG1qznjXVCf3r+fVHhm4efTYVsySA== +"@babel/generator@^7.4.4", "@babel/generator@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e" + integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA== dependencies: - "@babel/types" "^7.6.0" + "@babel/types" "^7.8.3" jsesc "^2.5.1" lodash "^4.17.13" source-map "^0.5.0" - trim-right "^1.0.1" -"@babel/helper-annotate-as-pure@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" - integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q== +"@babel/helper-annotate-as-pure@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" + integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== dependencies: - "@babel/types" "^7.0.0" + "@babel/types" "^7.8.3" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" - integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503" + integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw== dependencies: - "@babel/helper-explode-assignable-expression" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/helper-explode-assignable-expression" "^7.8.3" + "@babel/types" "^7.8.3" -"@babel/helper-call-delegate@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43" - integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ== +"@babel/helper-builder-react-jsx@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.8.3.tgz#dee98d7d79cc1f003d80b76fe01c7f8945665ff6" + integrity sha512-JT8mfnpTkKNCboTqZsQTdGo3l3Ik3l7QIt9hh0O9DYiwVel37VoJpILKM4YFbP2euF32nkQSb+F9cUk9b7DDXQ== dependencies: - "@babel/helper-hoist-variables" "^7.4.4" - "@babel/traverse" "^7.4.4" - "@babel/types" "^7.4.4" + "@babel/types" "^7.8.3" + esutils "^2.0.0" -"@babel/helper-define-map@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz#3dec32c2046f37e09b28c93eb0b103fd2a25d369" - integrity sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg== +"@babel/helper-call-delegate@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692" + integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A== dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/types" "^7.5.5" + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-compilation-targets@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.4.tgz#03d7ecd454b7ebe19a254f76617e61770aed2c88" + integrity sha512-3k3BsKMvPp5bjxgMdrFyq0UaEO48HciVrOVF0+lon8pp95cyJ2ujAh0TrBHNMnJGT2rr0iKOJPFFbSqjDyf/Pg== + dependencies: + "@babel/compat-data" "^7.8.4" + browserslist "^4.8.5" + invariant "^2.2.4" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/helper-create-class-features-plugin@^7.3.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz#5b94be88c255f140fd2c10dd151e7f98f4bff397" + integrity sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + +"@babel/helper-create-regexp-features-plugin@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz#c774268c95ec07ee92476a3862b75cc2839beb79" + integrity sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q== + dependencies: + "@babel/helper-regex" "^7.8.3" + regexpu-core "^4.6.0" + +"@babel/helper-define-map@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" + integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/types" "^7.8.3" lodash "^4.17.13" -"@babel/helper-explode-assignable-expression@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" - integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA== +"@babel/helper-explode-assignable-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982" + integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw== dependencies: - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" -"@babel/helper-function-name@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" - integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== +"@babel/helper-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" + integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== dependencies: - "@babel/helper-get-function-arity" "^7.0.0" - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" -"@babel/helper-get-function-arity@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" - integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== +"@babel/helper-get-function-arity@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" + integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== dependencies: - "@babel/types" "^7.0.0" + "@babel/types" "^7.8.3" -"@babel/helper-hoist-variables@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a" - integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w== +"@babel/helper-hoist-variables@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" + integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg== dependencies: - "@babel/types" "^7.4.4" + "@babel/types" "^7.8.3" -"@babel/helper-member-expression-to-functions@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz#1fb5b8ec4453a93c439ee9fe3aeea4a84b76b590" - integrity sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA== +"@babel/helper-member-expression-to-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" + integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== dependencies: - "@babel/types" "^7.5.5" + "@babel/types" "^7.8.3" -"@babel/helper-module-imports@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" - integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" + integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== dependencies: - "@babel/types" "^7.0.0" + "@babel/types" "^7.8.3" -"@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz#f84ff8a09038dcbca1fd4355661a500937165b4a" - integrity sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw== +"@babel/helper-module-transforms@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590" + integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q== dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-simple-access" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.4" - "@babel/template" "^7.4.4" - "@babel/types" "^7.5.5" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" lodash "^4.17.13" -"@babel/helper-optimise-call-expression@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" - integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g== +"@babel/helper-optimise-call-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" + integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== dependencies: - "@babel/types" "^7.0.0" + "@babel/types" "^7.8.3" -"@babel/helper-plugin-utils@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" - integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" + integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== -"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.5.5.tgz#0aa6824f7100a2e0e89c1527c23936c152cab351" - integrity sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw== +"@babel/helper-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" + integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ== dependencies: lodash "^4.17.13" -"@babel/helper-remap-async-to-generator@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" - integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-wrap-function" "^7.1.0" - "@babel/template" "^7.1.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-replace-supers@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz#f84ce43df031222d2bad068d2626cb5799c34bc2" - integrity sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.5.5" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/traverse" "^7.5.5" - "@babel/types" "^7.5.5" - -"@babel/helper-simple-access@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" - integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w== +"@babel/helper-remap-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86" + integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-wrap-function" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-replace-supers@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc" + integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-simple-access@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" + integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== + dependencies: + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-split-export-declaration@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" + integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-wrap-function@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" + integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helpers@^7.4.4", "@babel/helpers@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.4.tgz#754eb3ee727c165e0a240d6c207de7c455f36f73" + integrity sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w== + dependencies: + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.4" + "@babel/types" "^7.8.3" + +"@babel/highlight@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" + integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== dependencies: - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" -"@babel/helper-split-export-declaration@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" - integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== +"@babel/parser@^7.4.5", "@babel/parser@^7.8.3", "@babel/parser@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8" + integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw== + +"@babel/plugin-proposal-async-generator-functions@^7.2.0", "@babel/plugin-proposal-async-generator-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" + integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== dependencies: - "@babel/types" "^7.4.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" -"@babel/helper-wrap-function@^7.1.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" - integrity sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ== +"@babel/plugin-proposal-class-properties@7.3.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.0.tgz#272636bc0fa19a0bc46e601ec78136a173ea36cd" + integrity sha512-wNHxLkEKTQ2ay0tnsam2z7fGZUi+05ziDJflEt3AZTP3oXLKHJp9HqhfroB/vdMvt3sda9fAbq7FsG8QPDrZBg== dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/template" "^7.1.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.2.0" + "@babel/helper-create-class-features-plugin" "^7.3.0" + "@babel/helper-plugin-utils" "^7.0.0" -"@babel/helpers@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.6.0.tgz#21961d16c6a3c3ab597325c34c465c0887d31c6e" - integrity sha512-W9kao7OBleOjfXtFGgArGRX6eCP0UEcA2ZWEWNkJdRZnHhW4eEbeswbG3EwaRsnQUAEGWYgMq1HsIXuNNNy2eQ== +"@babel/plugin-proposal-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054" + integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w== dependencies: - "@babel/template" "^7.6.0" - "@babel/traverse" "^7.6.0" - "@babel/types" "^7.6.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" -"@babel/highlight@^7.0.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" - integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== +"@babel/plugin-proposal-json-strings@^7.2.0", "@babel/plugin-proposal-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" + integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q== dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^4.0.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" -"@babel/parser@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.0.tgz#3e05d0647432a8326cb28d0de03895ae5a57f39b" - integrity sha512-+o2q111WEx4srBs7L9eJmcwi655eD8sXniLqMB93TBK9GrNzGrxDWSjiqz2hLU0Ha8MTXFIP0yd9fNdP+m43ZQ== +"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2" + integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" -"@babel/plugin-proposal-async-generator-functions@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" - integrity sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ== +"@babel/plugin-proposal-object-rest-spread@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.2.tgz#6d1859882d4d778578e41f82cc5d7bf3d5daf6c1" + integrity sha512-DjeMS+J2+lpANkYLLO+m6GjoTMygYglKmRe6cDTbFv3L9i6mmiE8fe6B8MtCSLZpVXscD5kn7s6SgtHrDoBWoA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.1.0" - "@babel/plugin-syntax-async-generators" "^7.2.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" -"@babel/plugin-proposal-dynamic-import@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz#e532202db4838723691b10a67b8ce509e397c506" - integrity sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw== +"@babel/plugin-proposal-object-rest-spread@^7.4.4", "@babel/plugin-proposal-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb" + integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-dynamic-import" "^7.2.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" -"@babel/plugin-proposal-json-strings@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" - integrity sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg== +"@babel/plugin-proposal-optional-catch-binding@^7.2.0", "@babel/plugin-proposal-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" + integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-json-strings" "^7.2.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" -"@babel/plugin-proposal-object-rest-spread@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz#61939744f71ba76a3ae46b5eea18a54c16d22e58" - integrity sha512-F2DxJJSQ7f64FyTVl5cw/9MWn6naXGdk3Q3UhDbFEEHv+EilCPoeRD3Zh/Utx1CJz4uyKlQ4uH+bJPbEhMV7Zw== +"@babel/plugin-proposal-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.8.3.tgz#ae10b3214cb25f7adb1f3bc87ba42ca10b7e2543" + integrity sha512-QIoIR9abkVn+seDE3OjA08jWcs3eZ9+wJCKSRgo3WdEU2csFYgdScb+8qHB3+WXsGJD55u+5hWCISI7ejXS+kg== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" -"@babel/plugin-proposal-optional-catch-binding@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" - integrity sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g== +"@babel/plugin-proposal-unicode-property-regex@^7.4.4", "@babel/plugin-proposal-unicode-property-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz#b646c3adea5f98800c9ab45105ac34d06cd4a47f" + integrity sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz#501ffd9826c0b91da22690720722ac7cb1ca9c78" - integrity sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA== +"@babel/plugin-syntax-async-generators@^7.2.0", "@babel/plugin-syntax-async-generators@^7.8.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.5.4" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-async-generators@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f" - integrity sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg== +"@babel/plugin-syntax-dynamic-import@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-dynamic-import@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612" - integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w== +"@babel/plugin-syntax-json-strings@^7.2.0", "@babel/plugin-syntax-json-strings@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-json-strings@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" - integrity sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg== +"@babel/plugin-syntax-jsx@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.8.3.tgz#521b06c83c40480f1e58b4fd33b92eceb1d6ea94" + integrity sha512-WxdW9xyLgBdefoo0Ynn3MRSkhe5tFVxxKNVdnZSh318WrG2e2jH+E9wd/++JsqcLJZPfz87njQJ8j2Upjm0M0A== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-object-rest-spread@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" - integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-catch-binding@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" - integrity sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w== +"@babel/plugin-syntax-object-rest-spread@^7.2.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-transform-arrow-functions@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" - integrity sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg== +"@babel/plugin-syntax-optional-catch-binding@^7.2.0", "@babel/plugin-syntax-optional-catch-binding@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-transform-async-to-generator@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e" - integrity sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg== +"@babel/plugin-syntax-optional-chaining@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.1.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-transform-block-scoped-functions@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" - integrity sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w== +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391" + integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-block-scoping@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.0.tgz#c49e21228c4bbd4068a35667e6d951c75439b1dc" - integrity sha512-tIt4E23+kw6TgL/edACZwP1OUKrjOTyMrFMLoT5IOFrfMRabCgekjqFd5o6PaAMildBu46oFkekIdMuGkkPEpA== +"@babel/plugin-transform-arrow-functions@^7.2.0", "@babel/plugin-transform-arrow-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6" + integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - lodash "^4.17.13" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-classes@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz#d094299d9bd680a14a2a0edae38305ad60fb4de9" - integrity sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg== +"@babel/plugin-transform-async-to-generator@^7.4.4", "@babel/plugin-transform-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" + integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-define-map" "^7.5.5" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.5.5" - "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + +"@babel/plugin-transform-block-scoped-functions@^7.2.0", "@babel/plugin-transform-block-scoped-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" + integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-block-scoping@^7.4.4", "@babel/plugin-transform-block-scoping@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" + integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + lodash "^4.17.13" + +"@babel/plugin-transform-classes@^7.4.4", "@babel/plugin-transform-classes@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8" + integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-define-map" "^7.8.3" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" - integrity sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA== +"@babel/plugin-transform-computed-properties@^7.2.0", "@babel/plugin-transform-computed-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" + integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-destructuring@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.6.0.tgz#44bbe08b57f4480094d57d9ffbcd96d309075ba6" - integrity sha512-2bGIS5P1v4+sWTCnKNDZDxbGvEqi0ijeqM/YqHtVGrvG2y0ySgnEEhXErvE9dA0bnIzY9bIzdFK0jFA46ASIIQ== +"@babel/plugin-transform-destructuring@^7.4.4", "@babel/plugin-transform-destructuring@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz#20ddfbd9e4676906b1056ee60af88590cc7aaa0b" + integrity sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz#361a148bc951444312c69446d76ed1ea8e4450c3" - integrity sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg== +"@babel/plugin-transform-dotall-regex@^7.4.4", "@babel/plugin-transform-dotall-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" + integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.5.4" + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-duplicate-keys@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853" - integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ== +"@babel/plugin-transform-duplicate-keys@^7.2.0", "@babel/plugin-transform-duplicate-keys@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1" + integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-exponentiation-operator@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" - integrity sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A== +"@babel/plugin-transform-exponentiation-operator@^7.2.0", "@babel/plugin-transform-exponentiation-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7" + integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-for-of@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556" - integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ== +"@babel/plugin-transform-for-of@^7.4.4", "@babel/plugin-transform-for-of@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz#6fe8eae5d6875086ee185dd0b098a8513783b47d" + integrity sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-function-name@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad" - integrity sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA== +"@babel/plugin-transform-function-name@^7.4.4", "@babel/plugin-transform-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" + integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-literals@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" - integrity sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg== +"@babel/plugin-transform-literals@^7.2.0", "@babel/plugin-transform-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" + integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-member-expression-literals@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz#fa10aa5c58a2cb6afcf2c9ffa8cb4d8b3d489a2d" - integrity sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA== +"@babel/plugin-transform-member-expression-literals@^7.2.0", "@babel/plugin-transform-member-expression-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410" + integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-modules-amd@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91" - integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg== +"@babel/plugin-transform-modules-amd@^7.2.0", "@babel/plugin-transform-modules-amd@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5" + integrity sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ== dependencies: - "@babel/helper-module-transforms" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-commonjs@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.6.0.tgz#39dfe957de4420445f1fcf88b68a2e4aa4515486" - integrity sha512-Ma93Ix95PNSEngqomy5LSBMAQvYKVe3dy+JlVJSHEXZR5ASL9lQBedMiCyVtmTLraIDVRE3ZjTZvmXXD2Ozw3g== +"@babel/plugin-transform-modules-commonjs@7.8.3", "@babel/plugin-transform-modules-commonjs@^7.4.4", "@babel/plugin-transform-modules-commonjs@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz#df251706ec331bd058a34bdd72613915f82928a5" + integrity sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg== dependencies: - "@babel/helper-module-transforms" "^7.4.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-simple-access" "^7.1.0" + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-systemjs@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz#e75266a13ef94202db2a0620977756f51d52d249" - integrity sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg== +"@babel/plugin-transform-modules-systemjs@^7.4.4", "@babel/plugin-transform-modules-systemjs@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz#d8bbf222c1dbe3661f440f2f00c16e9bb7d0d420" + integrity sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg== dependencies: - "@babel/helper-hoist-variables" "^7.4.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-umd@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae" - integrity sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw== +"@babel/plugin-transform-modules-umd@^7.2.0", "@babel/plugin-transform-modules-umd@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz#592d578ce06c52f5b98b02f913d653ffe972661a" + integrity sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw== dependencies: - "@babel/helper-module-transforms" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-named-capturing-groups-regex@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.0.tgz#1e6e663097813bb4f53d42df0750cf28ad3bb3f1" - integrity sha512-jem7uytlmrRl3iCAuQyw8BpB4c4LWvSpvIeXKpMb+7j84lkx4m4mYr5ErAcmN5KM7B6BqrAvRGjBIbbzqCczew== +"@babel/plugin-transform-named-capturing-groups-regex@^7.4.5", "@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" + integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== dependencies: - regexp-tree "^0.1.13" + "@babel/helper-create-regexp-features-plugin" "^7.8.3" -"@babel/plugin-transform-new-target@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz#18d120438b0cc9ee95a47f2c72bc9768fbed60a5" - integrity sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA== +"@babel/plugin-transform-new-target@^7.4.4", "@babel/plugin-transform-new-target@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" + integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-object-super@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz#c70021df834073c65eb613b8679cc4a381d1a9f9" - integrity sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ== +"@babel/plugin-transform-object-super@^7.2.0", "@babel/plugin-transform-object-super@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" + integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.5.5" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" -"@babel/plugin-transform-parameters@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16" - integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw== +"@babel/plugin-transform-parameters@^7.4.4", "@babel/plugin-transform-parameters@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.4.tgz#1d5155de0b65db0ccf9971165745d3bb990d77d3" + integrity sha512-IsS3oTxeTsZlE5KqzTbcC2sV0P9pXdec53SU+Yxv7o/6dvGM5AkTotQKhoSffhNgZ/dftsSiOoxy7evCYJXzVA== dependencies: - "@babel/helper-call-delegate" "^7.4.4" - "@babel/helper-get-function-arity" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-call-delegate" "^7.8.3" + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-property-literals@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz#03e33f653f5b25c4eb572c98b9485055b389e905" - integrity sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ== +"@babel/plugin-transform-property-literals@^7.2.0", "@babel/plugin-transform-property-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" + integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-regenerator@^7.4.5": - version "7.4.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz#629dc82512c55cee01341fb27bdfcb210354680f" - integrity sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA== +"@babel/plugin-transform-react-display-name@^7.0.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz#70ded987c91609f78353dd76d2fb2a0bb991e8e5" + integrity sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-react-jsx-self@^7.0.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.8.3.tgz#c4f178b2aa588ecfa8d077ea80d4194ee77ed702" + integrity sha512-01OT7s5oa0XTLf2I8XGsL8+KqV9lx3EZV+jxn/L2LQ97CGKila2YMroTkCEIE0HV/FF7CMSRsIAybopdN9NTdg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-jsx" "^7.8.3" + +"@babel/plugin-transform-react-jsx-source@^7.0.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.8.3.tgz#951e75a8af47f9f120db731be095d2b2c34920e0" + integrity sha512-PLMgdMGuVDtRS/SzjNEQYUT8f4z1xb2BAT54vM1X5efkVuYBf5WyGUMbpmARcfq3NaglIwz08UVQK4HHHbC6ag== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-jsx" "^7.8.3" + +"@babel/plugin-transform-react-jsx@^7.0.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.8.3.tgz#4220349c0390fdefa505365f68c103562ab2fc4a" + integrity sha512-r0h+mUiyL595ikykci+fbwm9YzmuOrUBi0b+FDIKmi3fPQyFokWVEMJnRWHJPPQEjyFJyna9WZC6Viv6UHSv1g== + dependencies: + "@babel/helper-builder-react-jsx" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-jsx" "^7.8.3" + +"@babel/plugin-transform-regenerator@^7.4.5", "@babel/plugin-transform-regenerator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8" + integrity sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA== dependencies: regenerator-transform "^0.14.0" -"@babel/plugin-transform-reserved-words@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz#4792af87c998a49367597d07fedf02636d2e1634" - integrity sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw== +"@babel/plugin-transform-reserved-words@^7.2.0", "@babel/plugin-transform-reserved-words@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5" + integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-shorthand-properties@^7.2.0": +"@babel/plugin-transform-runtime@7.2.0": version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" - integrity sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz#566bc43f7d0aedc880eaddbd29168d0f248966ea" + integrity sha512-jIgkljDdq4RYDnJyQsiWbdvGeei/0MOTtSHKO/rfbd/mXBxNpdlulMx49L0HQ4pug1fXannxoqCI+fYSle9eSw== dependencies: + "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" + resolve "^1.8.1" + semver "^5.5.1" -"@babel/plugin-transform-spread@^7.2.0": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406" - integrity sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w== +"@babel/plugin-transform-shorthand-properties@^7.2.0", "@babel/plugin-transform-shorthand-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" + integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-sticky-regex@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" - integrity sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw== +"@babel/plugin-transform-spread@^7.2.0", "@babel/plugin-transform-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8" + integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-template-literals@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0" - integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g== +"@babel/plugin-transform-sticky-regex@^7.2.0", "@babel/plugin-transform-sticky-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" + integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-regex" "^7.8.3" -"@babel/plugin-transform-typeof-symbol@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" - integrity sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw== +"@babel/plugin-transform-template-literals@^7.4.4", "@babel/plugin-transform-template-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80" + integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-unicode-regex@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f" - integrity sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA== +"@babel/plugin-transform-typeof-symbol@^7.2.0", "@babel/plugin-transform-typeof-symbol@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" + integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.5.4" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/preset-env@^7.0.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.6.0.tgz#aae4141c506100bb2bfaa4ac2a5c12b395619e50" - integrity sha512-1efzxFv/TcPsNXlRhMzRnkBFMeIqBBgzwmZwlFDw5Ubj0AGLeufxugirwZmkkX/ayi3owsSqoQ4fw8LkfK9SYg== +"@babel/plugin-transform-unicode-regex@^7.4.4", "@babel/plugin-transform-unicode-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" + integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/preset-env@7.4.5": + version "7.4.5" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.4.5.tgz#2fad7f62983d5af563b5f3139242755884998a58" + integrity sha512-f2yNVXM+FsR5V8UwcFeIHzHWgnhXg3NpRmy0ADvALpnhB0SLbCvrCRr4BLOUYbQNLS+Z0Yer46x9dJXpXewI7w== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-async-generator-functions" "^7.2.0" - "@babel/plugin-proposal-dynamic-import" "^7.5.0" "@babel/plugin-proposal-json-strings" "^7.2.0" - "@babel/plugin-proposal-object-rest-spread" "^7.5.5" + "@babel/plugin-proposal-object-rest-spread" "^7.4.4" "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" "@babel/plugin-syntax-async-generators" "^7.2.0" - "@babel/plugin-syntax-dynamic-import" "^7.2.0" "@babel/plugin-syntax-json-strings" "^7.2.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" "@babel/plugin-transform-arrow-functions" "^7.2.0" - "@babel/plugin-transform-async-to-generator" "^7.5.0" + "@babel/plugin-transform-async-to-generator" "^7.4.4" "@babel/plugin-transform-block-scoped-functions" "^7.2.0" - "@babel/plugin-transform-block-scoping" "^7.6.0" - "@babel/plugin-transform-classes" "^7.5.5" + "@babel/plugin-transform-block-scoping" "^7.4.4" + "@babel/plugin-transform-classes" "^7.4.4" "@babel/plugin-transform-computed-properties" "^7.2.0" - "@babel/plugin-transform-destructuring" "^7.6.0" + "@babel/plugin-transform-destructuring" "^7.4.4" "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/plugin-transform-duplicate-keys" "^7.5.0" + "@babel/plugin-transform-duplicate-keys" "^7.2.0" "@babel/plugin-transform-exponentiation-operator" "^7.2.0" "@babel/plugin-transform-for-of" "^7.4.4" "@babel/plugin-transform-function-name" "^7.4.4" "@babel/plugin-transform-literals" "^7.2.0" "@babel/plugin-transform-member-expression-literals" "^7.2.0" - "@babel/plugin-transform-modules-amd" "^7.5.0" - "@babel/plugin-transform-modules-commonjs" "^7.6.0" - "@babel/plugin-transform-modules-systemjs" "^7.5.0" + "@babel/plugin-transform-modules-amd" "^7.2.0" + "@babel/plugin-transform-modules-commonjs" "^7.4.4" + "@babel/plugin-transform-modules-systemjs" "^7.4.4" "@babel/plugin-transform-modules-umd" "^7.2.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.6.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.4.5" "@babel/plugin-transform-new-target" "^7.4.4" - "@babel/plugin-transform-object-super" "^7.5.5" + "@babel/plugin-transform-object-super" "^7.2.0" "@babel/plugin-transform-parameters" "^7.4.4" "@babel/plugin-transform-property-literals" "^7.2.0" "@babel/plugin-transform-regenerator" "^7.4.5" @@ -598,46 +764,150 @@ "@babel/plugin-transform-template-literals" "^7.4.4" "@babel/plugin-transform-typeof-symbol" "^7.2.0" "@babel/plugin-transform-unicode-regex" "^7.4.4" - "@babel/types" "^7.6.0" + "@babel/types" "^7.4.4" browserslist "^4.6.0" core-js-compat "^3.1.1" invariant "^2.2.2" js-levenshtein "^1.1.3" semver "^5.5.0" -"@babel/template@^7.1.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6" - integrity sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ== +"@babel/preset-env@^7.0.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.4.tgz#9dac6df5f423015d3d49b6e9e5fa3413e4a72c4e" + integrity sha512-HihCgpr45AnSOHRbS5cWNTINs0TwaR8BS8xIIH+QwiW8cKL0llV91njQMpeMReEPVs+1Ao0x3RLEBLtt1hOq4w== + dependencies: + "@babel/compat-data" "^7.8.4" + "@babel/helper-compilation-targets" "^7.8.4" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-proposal-async-generator-functions" "^7.8.3" + "@babel/plugin-proposal-dynamic-import" "^7.8.3" + "@babel/plugin-proposal-json-strings" "^7.8.3" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-proposal-object-rest-spread" "^7.8.3" + "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining" "^7.8.3" + "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-transform-arrow-functions" "^7.8.3" + "@babel/plugin-transform-async-to-generator" "^7.8.3" + "@babel/plugin-transform-block-scoped-functions" "^7.8.3" + "@babel/plugin-transform-block-scoping" "^7.8.3" + "@babel/plugin-transform-classes" "^7.8.3" + "@babel/plugin-transform-computed-properties" "^7.8.3" + "@babel/plugin-transform-destructuring" "^7.8.3" + "@babel/plugin-transform-dotall-regex" "^7.8.3" + "@babel/plugin-transform-duplicate-keys" "^7.8.3" + "@babel/plugin-transform-exponentiation-operator" "^7.8.3" + "@babel/plugin-transform-for-of" "^7.8.4" + "@babel/plugin-transform-function-name" "^7.8.3" + "@babel/plugin-transform-literals" "^7.8.3" + "@babel/plugin-transform-member-expression-literals" "^7.8.3" + "@babel/plugin-transform-modules-amd" "^7.8.3" + "@babel/plugin-transform-modules-commonjs" "^7.8.3" + "@babel/plugin-transform-modules-systemjs" "^7.8.3" + "@babel/plugin-transform-modules-umd" "^7.8.3" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" + "@babel/plugin-transform-new-target" "^7.8.3" + "@babel/plugin-transform-object-super" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.8.4" + "@babel/plugin-transform-property-literals" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.3" + "@babel/plugin-transform-reserved-words" "^7.8.3" + "@babel/plugin-transform-shorthand-properties" "^7.8.3" + "@babel/plugin-transform-spread" "^7.8.3" + "@babel/plugin-transform-sticky-regex" "^7.8.3" + "@babel/plugin-transform-template-literals" "^7.8.3" + "@babel/plugin-transform-typeof-symbol" "^7.8.4" + "@babel/plugin-transform-unicode-regex" "^7.8.3" + "@babel/types" "^7.8.3" + browserslist "^4.8.5" + core-js-compat "^3.6.2" + invariant "^2.2.2" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/preset-react@7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.0.0.tgz#e86b4b3d99433c7b3e9e91747e2653958bc6b3c0" + integrity sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w== dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.6.0" - "@babel/types" "^7.6.0" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.5", "@babel/traverse@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.6.0.tgz#389391d510f79be7ce2ddd6717be66d3fed4b516" - integrity sha512-93t52SaOBgml/xY74lsmt7xOR4ufYvhb5c5qiM6lu4J/dWGMAfAh6eKw4PjLes6DI6nQgearoxnFJk60YchpvQ== - dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.6.0" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.4" - "@babel/parser" "^7.6.0" - "@babel/types" "^7.6.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-react-jsx-self" "^7.0.0" + "@babel/plugin-transform-react-jsx-source" "^7.0.0" + +"@babel/runtime@7.3.1": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.1.tgz#574b03e8e8a9898eaf4a872a92ea20b7846f6f2a" + integrity sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA== + dependencies: + regenerator-runtime "^0.12.0" + +"@babel/template@^7.4.4", "@babel/template@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" + integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/traverse@^7.4.5", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.4.tgz#f0845822365f9d5b0e312ed3959d3f827f869e3c" + integrity sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.4" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.8.4" + "@babel/types" "^7.8.3" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.13" -"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.6.0": - version "7.6.1" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.6.1.tgz#53abf3308add3ac2a2884d539151c57c4b3ac648" - integrity sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g== +"@babel/types@^7.4.4", "@babel/types@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" + integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg== dependencies: esutils "^2.0.2" lodash "^4.17.13" to-fast-properties "^2.0.0" +"@cypress/browserify-preprocessor@^2.1.1": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@cypress/browserify-preprocessor/-/browserify-preprocessor-2.1.3.tgz#abbb8ba52ff33d70745c056e8fc675db2276a539" + integrity sha512-vZskc/EKejnmdm4fMGB1Fm39WelsF4HJHeI5q8I0LvGnrdvxSiCbn27TbhCM5Enq6Fkinf3f7oiHS/m2OUgzdA== + dependencies: + "@babel/core" "7.4.5" + "@babel/plugin-proposal-class-properties" "7.3.0" + "@babel/plugin-proposal-object-rest-spread" "7.3.2" + "@babel/plugin-transform-modules-commonjs" "7.8.3" + "@babel/plugin-transform-runtime" "7.2.0" + "@babel/preset-env" "7.4.5" + "@babel/preset-react" "7.0.0" + "@babel/runtime" "7.3.1" + babelify "10.0.0" + bluebird "3.5.3" + browserify "16.2.3" + coffeeify "3.0.1" + coffeescript "1.12.7" + debug "4.1.1" + fs-extra "7.0.1" + lodash.clonedeep "4.5.0" + watchify "3.11.1" + "@cypress/listr-verbose-renderer@0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@cypress/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#a77492f4b11dcc7c446a34b3e28721afd33c642a" @@ -649,26 +919,26 @@ figures "^1.7.0" "@cypress/snapshot@^2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@cypress/snapshot/-/snapshot-2.1.3.tgz#85f5c40c4c27df9185773062a5d29e3f1a8d0b1f" - integrity sha512-NAkyxFxeFSJt6K/McsF3u8RoSqLi3trYlO5ZkfoeiKcNm8J0eX4o6Uz12xMPcfTi5Ql9RMyZg6/j6XJU6tBjiQ== + version "2.1.7" + resolved "https://registry.yarnpkg.com/@cypress/snapshot/-/snapshot-2.1.7.tgz#e7360eb628b062f28f03036382619ec72cfb1831" + integrity sha512-f8AcfIg7wOOHSdBODlIwCJE/rG5Yb+kUY+WVTKynB2pLLoDy9nc8CtcazqX19q2Lh++nTJLNRihpbbWvk33mbg== dependencies: - "@wildpeaks/snapshot-dom" "1.2.1" + "@wildpeaks/snapshot-dom" "1.6.0" am-i-a-dependency "1.1.2" check-more-types "2.24.0" its-name "1.0.0" - js-beautify "1.10.0" + js-beautify "1.10.3" lazy-ass "1.6.0" snap-shot-compare "2.8.3" snap-shot-store "1.2.3" "@cypress/webpack-preprocessor@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-4.1.0.tgz#8c4debc0b1abf045b62524d1996dd9aeaf7e86a8" - integrity sha512-LbxsdYVpHGoC2fMOdW0aQvuvVRD7aZx8p8DrP53HISpl7bD1PqLGWKzhHn7cGG24UHycBJrbaEeKEosW29W1dg== + version "4.1.1" + resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-4.1.1.tgz#3c0b5b8de6eaac605dac3b1f1c3f5916c1c6eaea" + integrity sha512-SfzDqOvWBSlfGRm8ak/XHUXAnndwHU2qJIRr1LIC7j2UqWcZoJ+286CuNloJbkwfyEAO6tQggLd4E/WHUAcKZQ== dependencies: - bluebird "3.5.0" - debug "3.1.0" + bluebird "3.7.1" + debug "4.1.1" optionalDependencies: "@babel/core" "^7.0.1" "@babel/preset-env" "^7.0.0" @@ -682,10 +952,25 @@ debug "^3.1.0" lodash.once "^4.1.1" +"@types/cypress-cucumber-preprocessor@^1.14.0": + version "1.14.0" + resolved "https://registry.yarnpkg.com/@types/cypress-cucumber-preprocessor/-/cypress-cucumber-preprocessor-1.14.0.tgz#41d8ffb2b608d3ed4ab998a0c4394056f75af1e0" + integrity sha512-bOl4u6seZtxNIGa6J6xydroPntTxxWy8uqIrZ3OY10C96fUes4mZvJKY6NvOoe61/OVafG/UEFa+X2ZWKE6Ltw== + "@types/js-yaml@^3.12.1": - version "3.12.1" - resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.1.tgz#5c6f4a1eabca84792fbd916f0cb40847f123c656" - integrity sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA== + version "3.12.2" + resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.2.tgz#a35a1809c33a68200fb6403d1ad708363c56470a" + integrity sha512-0CFu/g4mDSNkodVwWijdlr8jH7RoplRWNgovjFLEZeT+QEbbZXjBmCe3HwaWheAlCbHwomTwzZoSedeOycABug== + +"@types/node@^10.12.11": + version "10.17.14" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.14.tgz#b6c60ebf2fb5e4229fdd751ff9ddfae0f5f31541" + integrity sha512-G0UmX5uKEmW+ZAhmZ6PLTQ5eu/VPaT+d/tdLd5IFsKRPcbe6lPxocBtcYBFSaLaCW8O60AX90e91Nsp8lVHCNw== + +"@types/sizzle@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" + integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg== "@webassemblyjs/ast@1.8.5": version "1.8.5" @@ -833,10 +1118,10 @@ "@webassemblyjs/wast-parser" "1.8.5" "@xtuc/long" "4.2.2" -"@wildpeaks/snapshot-dom@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@wildpeaks/snapshot-dom/-/snapshot-dom-1.2.1.tgz#c4af08cdb175d61dca2878c7a2d91253158f6086" - integrity sha1-xK8IzbF11h3KKHjHotkSUxWPYIY= +"@wildpeaks/snapshot-dom@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@wildpeaks/snapshot-dom/-/snapshot-dom-1.6.0.tgz#83297612bf93b97983beafbe6ae71672642ac884" + integrity sha512-fCM5tYK6VZ1nhbk3Q11lkf6UOJlOCRU0oScQ8NV8OYBPC58wQmQaOF9g+rk+yhNYf3beybOBr+ZuiNen3B0Bxw== "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -848,15 +1133,42 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +JSONStream@^1.0.3: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +acorn-node@^1.2.0, acorn-node@^1.3.0, acorn-node@^1.5.2, acorn-node@^1.6.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" + integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== + dependencies: + acorn "^7.0.0" + acorn-walk "^7.0.0" + xtend "^4.0.2" + +acorn-walk@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.0.tgz#48387aa9a83bba67a9909164acab4bbc5796cf87" + integrity sha512-4ufNLdC8gOf1dlOjC1nrn2NfzevyDtrDPp/DOtmoOHAFA/1pQc6bWf7oZ71qDURTODPLQ03+oFOvwxq5BvjXug== + acorn@^6.2.1: - version "6.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e" - integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA== + version "6.4.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784" + integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw== + +acorn@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" + integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== ajv-errors@^1.0.0: version "1.0.1" @@ -869,11 +1181,11 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5: - version "6.10.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" - integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== + version "6.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9" + integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA== dependencies: - fast-deep-equal "^2.0.1" + fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" @@ -915,6 +1227,11 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -989,7 +1306,7 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= -assert@^1.1.1: +assert@^1.1.1, assert@^1.4.0: version "1.5.0" resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== @@ -997,6 +1314,20 @@ assert@^1.1.1: object-assign "^4.1.1" util "0.10.3" +assertion-error-formatter@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error-formatter/-/assertion-error-formatter-2.0.1.tgz#6bbdffaec8e2fa9e2b0eb158bfe353132d7c0a9b" + integrity sha512-cjC3jUCh9spkroKue5PDSKH5RFQ/KNuZJhk3GwHYmB/8qqETxLOmMdLH+ohi/VukNzxDlMvIe7zScvLoOdhb6Q== + dependencies: + diff "^3.0.0" + pad-right "^0.2.2" + repeat-string "^1.6.1" + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" @@ -1019,7 +1350,7 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -atob@^2.1.1: +atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== @@ -1030,9 +1361,9 @@ aws-sign2@~0.7.0: integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + version "1.9.1" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" + integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== babel-loader@^8.0.2: version "8.0.6" @@ -1051,6 +1382,19 @@ babel-plugin-dynamic-import-node@^2.3.0: dependencies: object.assign "^4.1.0" +babel-runtime@^6.11.6: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babelify@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/babelify/-/babelify-10.0.0.tgz#fe73b1a22583f06680d8d072e25a1e0d1d1d7fb5" + integrity sha512-X40FaxyH7t3X+JFAKvb1H9wooWKLRCi8pg3m8poqtdZaIng+bjzp9RvKQCvRjF9isHiPkXspbbXT/zwXLtwgwg== + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -1081,6 +1425,11 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +becke-ch--regex--s0-0-v1--base--pl--lib@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/becke-ch--regex--s0-0-v1--base--pl--lib/-/becke-ch--regex--s0-0-v1--base--pl--lib-1.4.0.tgz#429ceebbfa5f7e936e78d73fbdc7da7162b20e20" + integrity sha1-Qpzuu/pffpNueNc/vcfacWKyDiA= + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -1091,15 +1440,32 @@ binary-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + bluebird@3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" integrity sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw= -bluebird@^3.5.5: - version "3.5.5" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" - integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== +bluebird@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" + integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== + +bluebird@3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de" + integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg== + +bluebird@^3.4.1, bluebird@^3.5.5: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" @@ -1142,6 +1508,25 @@ brorand@^1.0.1: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= +browser-pack@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.1.0.tgz#c34ba10d0b9ce162b5af227c7131c92c2ecd5774" + integrity sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA== + dependencies: + JSONStream "^1.0.3" + combine-source-map "~0.8.0" + defined "^1.0.0" + safe-buffer "^5.1.1" + through2 "^2.0.0" + umd "^3.0.0" + +browser-resolve@^1.11.0, browser-resolve@^1.7.0: + version "1.11.3" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" + integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== + dependencies: + resolve "1.1.7" + browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" @@ -1194,21 +1579,129 @@ browserify-sign@^4.0.0: inherits "^2.0.1" parse-asn1 "^5.0.0" -browserify-zlib@^0.2.0: +browserify-zlib@^0.2.0, browserify-zlib@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== dependencies: pako "~1.0.5" -browserslist@^4.6.0, browserslist@^4.6.6: - version "4.7.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.0.tgz#9ee89225ffc07db03409f2fee524dc8227458a17" - integrity sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA== +browserify@16.2.3: + version "16.2.3" + resolved "https://registry.yarnpkg.com/browserify/-/browserify-16.2.3.tgz#7ee6e654ba4f92bce6ab3599c3485b1cc7a0ad0b" + integrity sha512-zQt/Gd1+W+IY+h/xX2NYMW4orQWhqSwyV+xsblycTtpOuB27h1fZhhNQuipJ4t79ohw4P4mMem0jp/ZkISQtjQ== + dependencies: + JSONStream "^1.0.3" + assert "^1.4.0" + browser-pack "^6.0.1" + browser-resolve "^1.11.0" + browserify-zlib "~0.2.0" + buffer "^5.0.2" + cached-path-relative "^1.0.0" + concat-stream "^1.6.0" + console-browserify "^1.1.0" + constants-browserify "~1.0.0" + crypto-browserify "^3.0.0" + defined "^1.0.0" + deps-sort "^2.0.0" + domain-browser "^1.2.0" + duplexer2 "~0.1.2" + events "^2.0.0" + glob "^7.1.0" + has "^1.0.0" + htmlescape "^1.1.0" + https-browserify "^1.0.0" + inherits "~2.0.1" + insert-module-globals "^7.0.0" + labeled-stream-splicer "^2.0.0" + mkdirp "^0.5.0" + module-deps "^6.0.0" + os-browserify "~0.3.0" + parents "^1.0.1" + path-browserify "~0.0.0" + process "~0.11.0" + punycode "^1.3.2" + querystring-es3 "~0.2.0" + read-only-stream "^2.0.0" + readable-stream "^2.0.2" + resolve "^1.1.4" + shasum "^1.0.0" + shell-quote "^1.6.1" + stream-browserify "^2.0.0" + stream-http "^2.0.0" + string_decoder "^1.1.1" + subarg "^1.0.0" + syntax-error "^1.1.1" + through2 "^2.0.0" + timers-browserify "^1.0.1" + tty-browserify "0.0.1" + url "~0.11.0" + util "~0.10.1" + vm-browserify "^1.0.0" + xtend "^4.0.0" + +browserify@^16.1.0: + version "16.5.0" + resolved "https://registry.yarnpkg.com/browserify/-/browserify-16.5.0.tgz#a1c2bc0431bec11fd29151941582e3f645ede881" + integrity sha512-6bfI3cl76YLAnCZ75AGu/XPOsqUhRyc0F/olGIJeCxtfxF2HvPKEcmjU9M8oAPxl4uBY1U7Nry33Q6koV3f2iw== + dependencies: + JSONStream "^1.0.3" + assert "^1.4.0" + browser-pack "^6.0.1" + browser-resolve "^1.11.0" + browserify-zlib "~0.2.0" + buffer "^5.0.2" + cached-path-relative "^1.0.0" + concat-stream "^1.6.0" + console-browserify "^1.1.0" + constants-browserify "~1.0.0" + crypto-browserify "^3.0.0" + defined "^1.0.0" + deps-sort "^2.0.0" + domain-browser "^1.2.0" + duplexer2 "~0.1.2" + events "^2.0.0" + glob "^7.1.0" + has "^1.0.0" + htmlescape "^1.1.0" + https-browserify "^1.0.0" + inherits "~2.0.1" + insert-module-globals "^7.0.0" + labeled-stream-splicer "^2.0.0" + mkdirp "^0.5.0" + module-deps "^6.0.0" + os-browserify "~0.3.0" + parents "^1.0.1" + path-browserify "~0.0.0" + process "~0.11.0" + punycode "^1.3.2" + querystring-es3 "~0.2.0" + read-only-stream "^2.0.0" + readable-stream "^2.0.2" + resolve "^1.1.4" + shasum "^1.0.0" + shell-quote "^1.6.1" + stream-browserify "^2.0.0" + stream-http "^3.0.0" + string_decoder "^1.1.1" + subarg "^1.0.0" + syntax-error "^1.1.1" + through2 "^2.0.0" + timers-browserify "^1.0.1" + tty-browserify "0.0.1" + url "~0.11.0" + util "~0.10.1" + vm-browserify "^1.0.0" + xtend "^4.0.0" + +browserslist@^4.6.0, browserslist@^4.8.3, browserslist@^4.8.5: + version "4.8.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.6.tgz#96406f3f5f0755d272e27a66f4163ca821590a7e" + integrity sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg== dependencies: - caniuse-lite "^1.0.30000989" - electron-to-chromium "^1.3.247" - node-releases "^1.1.29" + caniuse-lite "^1.0.30001023" + electron-to-chromium "^1.3.341" + node-releases "^1.1.47" buffer-crc32@~0.2.3: version "0.2.13" @@ -1226,14 +1719,22 @@ buffer-xor@^1.0.3: integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= buffer@^4.3.0: - version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" - integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" isarray "^1.0.0" +buffer@^5.0.2: + version "5.4.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115" + integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" @@ -1275,6 +1776,11 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +cached-path-relative@^1.0.0, cached-path-relative@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.2.tgz#a13df4196d26776220cc3356eb147a52dba2c6db" + integrity sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg== + cachedir@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-1.3.0.tgz#5e01928bf2d95b5edd94b0942188246740e0dbc4" @@ -1282,16 +1788,28 @@ cachedir@1.3.0: dependencies: os-homedir "^1.0.1" -caniuse-lite@^1.0.30000989: - version "1.0.30000989" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz#b9193e293ccf7e4426c5245134b8f2a56c0ac4b9" - integrity sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw== +caniuse-lite@^1.0.30001023: + version "1.0.30001027" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001027.tgz#283e2ef17d94889cc216a22c6f85303d78ca852d" + integrity sha512-7xvKeErvXZFtUItTHgNtLgS9RJpVnwBlWX8jSo/BO8VsF6deszemZSkJJJA1KOKrXuzZH4WALpAJdq5EyfgMLg== caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +chai@^4.1.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" + integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^3.0.1" + get-func-name "^2.0.0" + pathval "^1.1.0" + type-detect "^4.0.5" + chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -1312,12 +1830,17 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" +check-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= + check-more-types@2.24.0: version "2.24.0" resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" integrity sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA= -chokidar@^2.0.2: +chokidar@^2.0.2, chokidar@^2.0.4, chokidar@^2.1.1: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== @@ -1337,9 +1860,9 @@ chokidar@^2.0.2: fsevents "^1.2.7" chownr@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6" - integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A== + version "1.1.3" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" + integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== chrome-trace-event@^1.0.2: version "1.0.2" @@ -1383,6 +1906,13 @@ cli-spinners@^0.1.2: resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" integrity sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw= +cli-table@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM= + dependencies: + colors "1.0.3" + cli-truncate@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" @@ -1396,6 +1926,19 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= +coffeeify@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/coffeeify/-/coffeeify-3.0.1.tgz#5e2753000c50bd24c693115f33864248dd11136c" + integrity sha512-Qjnr7UX6ldK1PHV7wCnv7AuCd4q19KTUtwJnu/6JRJB4rfm12zvcXtKdacUoePOKr1I4ka/ydKiwWpNAdsQb0g== + dependencies: + convert-source-map "^1.3.0" + through2 "^2.0.0" + +coffeescript@1.12.7: + version "1.12.7" + resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-1.12.7.tgz#e57ee4c4867cf7f606bfc4a0f2d550c0981ddd27" + integrity sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA== + collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" @@ -1416,6 +1959,26 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= + +colors@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +combine-source-map@^0.8.0, combine-source-map@~0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.8.0.tgz#a58d0df042c186fcf822a8e8015f5450d2d79a8b" + integrity sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos= + dependencies: + convert-source-map "~1.1.0" + inline-source-map "~0.6.0" + lodash.memoize "~3.0.3" + source-map "~0.5.3" + combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -1428,10 +1991,10 @@ commander@2.15.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== -commander@^2.19.0, commander@^2.20.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" - integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== +commander@^2.19.0, commander@^2.20.0, commander@^2.9.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== common-tags@1.8.0: version "1.8.0" @@ -1453,7 +2016,7 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@1.6.2, concat-stream@^1.5.0: +concat-stream@1.6.2, concat-stream@^1.5.0, concat-stream@^1.6.0, concat-stream@^1.6.1, concat-stream@~1.6.0: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -1472,29 +2035,32 @@ config-chain@^1.1.12: proto-list "~1.2.1" console-browserify@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" - integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= - dependencies: - date-now "^0.1.4" + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -constants-browserify@^1.0.0: +constants-browserify@^1.0.0, constants-browserify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= -convert-source-map@^1.1.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" - integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== +convert-source-map@^1.1.0, convert-source-map@^1.3.0, convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== dependencies: safe-buffer "~5.1.1" +convert-source-map@~1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" + integrity sha1-SCnId+n+SbMWHzvzZziI4gRpmGA= + copy-concurrently@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" @@ -1512,19 +2078,34 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-js-compat@^3.1.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.2.1.tgz#0cbdbc2e386e8e00d3b85dc81c848effec5b8150" - integrity sha512-MwPZle5CF9dEaMYdDeWm73ao/IflDH+FjeJCWEADcEgFSE9TLimFKwJsfmkwzI8eC0Aj0mgvMDjeQjrElkz4/A== +core-js-compat@^3.1.1, core-js-compat@^3.6.2: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.4.tgz#938476569ebb6cda80d339bcf199fae4f16fff17" + integrity sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA== dependencies: - browserslist "^4.6.6" - semver "^6.3.0" + browserslist "^4.8.3" + semver "7.0.0" + +core-js@^2.4.0: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +cosmiconfig@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc" + integrity sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ== + dependencies: + is-directory "^0.3.1" + js-yaml "^3.9.0" + parse-json "^4.0.0" + require-from-string "^2.0.1" + create-ecdh@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" @@ -1567,7 +2148,7 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" -crypto-browserify@^3.11.0: +crypto-browserify@^3.0.0, crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== @@ -1584,18 +2165,91 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +cucumber-expressions@^5.0.13: + version "5.0.18" + resolved "https://registry.yarnpkg.com/cucumber-expressions/-/cucumber-expressions-5.0.18.tgz#6c70779efd3aebc5e9e7853938b1110322429596" + integrity sha1-bHB3nv0668Xp54U5OLERAyJClZY= + dependencies: + becke-ch--regex--s0-0-v1--base--pl--lib "^1.2.0" + +cucumber-expressions@^6.0.1: + version "6.6.2" + resolved "https://registry.yarnpkg.com/cucumber-expressions/-/cucumber-expressions-6.6.2.tgz#d89640eccc72a78380b6c210eae36a64e7462b81" + integrity sha512-WcFSVBiWNLJbIcAAC3t/ACU46vaOKfe1UIF5H3qveoq+Y4XQm9j3YwHurQNufRKBBg8nCnpU7Ttsx7egjS3hwA== + dependencies: + becke-ch--regex--s0-0-v1--base--pl--lib "^1.2.0" + +cucumber-tag-expressions@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/cucumber-tag-expressions/-/cucumber-tag-expressions-1.1.1.tgz#7f5c7b70009bc2b666591bfe64854578bedee85a" + integrity sha1-f1x7cACbwrZmWRv+ZIVFeL7e6Fo= + +cucumber@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/cucumber/-/cucumber-4.2.1.tgz#64cfff6150bbe6b5e94b173470057353d6206719" + integrity sha512-3gQ0Vv4kSHsvXEFC6b1c+TfLRDzWD1/kU7e5vm8Kh8j35b95k6favan9/4ixcBNqd7UsU1T6FYcawC87+DlNKw== + dependencies: + assertion-error-formatter "^2.0.1" + babel-runtime "^6.11.6" + bluebird "^3.4.1" + cli-table "^0.3.1" + colors "^1.1.2" + commander "^2.9.0" + cucumber-expressions "^5.0.13" + cucumber-tag-expressions "^1.1.1" + duration "^0.2.0" + escape-string-regexp "^1.0.5" + figures "2.0.0" + gherkin "^5.0.0" + glob "^7.0.0" + indent-string "^3.1.0" + is-generator "^1.0.2" + is-stream "^1.1.0" + knuth-shuffle-seeded "^1.0.6" + lodash "^4.17.4" + mz "^2.4.0" + progress "^2.0.0" + resolve "^1.3.3" + serialize-error "^2.1.0" + stack-chain "^2.0.0" + stacktrace-js "^2.0.0" + string-argv "0.0.2" + title-case "^2.1.1" + util-arity "^1.0.2" + verror "^1.9.0" + cyclist@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= -cypress@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.4.1.tgz#ca2e4e9864679da686c6a6189603efd409664c30" - integrity sha512-1HBS7t9XXzkt6QHbwfirWYty8vzxNMawGj1yI+Fu6C3/VZJ8UtUngMW6layqwYZzLTZV8tiDpdCNBypn78V4Dg== +cypress-cucumber-preprocessor@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/cypress-cucumber-preprocessor/-/cypress-cucumber-preprocessor-2.0.1.tgz#b6e64041efb4620ca559487152784bc044b35af5" + integrity sha512-i7WjLtv18O6/RoHeVLtfwNZmDL9DgPv4E8+6z5bQ4lqtBSjAKzRNrTnxAKAgUvaLK0TMeUm8GJu4eQ7B4LBqew== + dependencies: + "@cypress/browserify-preprocessor" "^2.1.1" + chai "^4.1.2" + chokidar "^2.0.4" + cosmiconfig "^4.0.0" + cucumber "^4.2.1" + cucumber-expressions "^6.0.1" + cucumber-tag-expressions "^1.1.1" + debug "^3.0.1" + gherkin "^5.1.0" + glob "^7.1.2" + js-string-escape "^1.0.1" + minimist "^1.2.0" + through "^2.3.8" + +cypress@^3.5.0: + version "3.8.3" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.8.3.tgz#e921f5482f1cbe5814891c878f26e704bbffd8f4" + integrity sha512-I9L/d+ilTPPA4vq3NC1OPKmw7jJIpMKNdyfR8t1EXYzYCjyqbc59migOm1YSse/VRbISLJ+QGb5k4Y3bz2lkYw== dependencies: "@cypress/listr-verbose-renderer" "0.4.1" "@cypress/xvfb" "1.2.4" + "@types/sizzle" "2.3.2" arch "2.1.1" bluebird "3.5.0" cachedir "1.3.0" @@ -1604,6 +2258,7 @@ cypress@^3.4.1: commander "2.15.1" common-tags "1.8.0" debug "3.2.6" + eventemitter2 "4.1.2" execa "0.10.0" executable "4.1.1" extract-zip "1.6.7" @@ -1622,9 +2277,23 @@ cypress@^3.4.1: request-progress "3.0.0" supports-color "5.5.0" tmp "0.1.0" + untildify "3.0.3" url "0.11.0" yauzl "2.10.0" +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +dash-ast@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dash-ast/-/dash-ast-1.0.0.tgz#12029ba5fb2f8aa6f0a861795b23c1b4b6c27d37" + integrity sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA== + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -1637,11 +2306,6 @@ date-fns@^1.27.2: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== -date-now@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" - integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= - debug@2.6.9, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -1656,7 +2320,7 @@ debug@3.1.0: dependencies: ms "2.0.0" -debug@3.2.6, debug@^3.1.0, debug@^3.2.6: +debug@3.2.6, debug@^3.0.1, debug@^3.1.0, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -1675,6 +2339,13 @@ decode-uri-component@^0.2.0: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= +deep-eql@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== + dependencies: + type-detect "^4.0.0" + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -1709,6 +2380,11 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -1719,10 +2395,20 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= +deps-sort@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.1.tgz#9dfdc876d2bcec3386b6829ac52162cda9fa208d" + integrity sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw== + dependencies: + JSONStream "^1.0.3" + shasum-object "^1.0.0" + subarg "^1.0.0" + through2 "^2.0.0" + des.js@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" - integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== dependencies: inherits "^2.0.1" minimalistic-assert "^1.0.0" @@ -1732,11 +2418,25 @@ detect-libc@^1.0.2: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +detective@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b" + integrity sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg== + dependencies: + acorn-node "^1.6.1" + defined "^1.0.0" + minimist "^1.1.1" + diff@^1.3.2: version "1.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" integrity sha1-fyjS657nsVqX79ic5j3P2qPMur8= +diff@^3.0.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -1754,11 +2454,18 @@ disparity@2.0.0: ansi-styles "^2.0.1" diff "^1.3.2" -domain-browser@^1.1.1: +domain-browser@^1.1.1, domain-browser@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== +duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= + dependencies: + readable-stream "^2.0.2" + duplexify@^3.4.2, duplexify@^3.6.0: version "3.7.1" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" @@ -1769,6 +2476,14 @@ duplexify@^3.4.2, duplexify@^3.6.0: readable-stream "^2.0.0" stream-shift "^1.0.0" +duration@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/duration/-/duration-0.2.2.tgz#ddf149bc3bc6901150fe9017111d016b3357f529" + integrity sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg== + dependencies: + d "1" + es5-ext "~0.10.46" + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -1787,10 +2502,10 @@ editorconfig@^0.15.3: semver "^5.6.0" sigmund "^1.0.1" -electron-to-chromium@^1.3.247: - version "1.3.258" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.258.tgz#829b03be37424099b91aefb6815e8801bf30b509" - integrity sha512-rkPYrgFU7k/8ngjHYvzOZ44OQQ1GeIRIQnhGv00RkSlQXEnJKsGonQppbEEWHuuxZegpMao+WZmYraWQJQJMMg== +electron-to-chromium@^1.3.341: + version "1.3.348" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.348.tgz#61fa7d43f6c4fd8b046b0b69213cb55b7a4c76a5" + integrity sha512-6O0IInybavGdYtcbI4ryF/9e3Qi8/soi6C68ELRseJuTwQPKq39uGgVVeQHG28t69Sgsky09nXBRhUiFXsZyFQ== elegant-spinner@^1.0.1: version "1.0.1" @@ -1798,9 +2513,9 @@ elegant-spinner@^1.0.1: integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4= elliptic@^6.0.0: - version "6.5.1" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.1.tgz#c380f5f909bf1b9b4428d028cd18d3b0efd6b52b" - integrity sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg== + version "6.5.2" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" + integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw== dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -1816,19 +2531,19 @@ emojis-list@^2.0.0: integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" - integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== + version "4.1.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" + integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA== dependencies: graceful-fs "^4.1.2" - memory-fs "^0.4.0" + memory-fs "^0.5.0" tapable "^1.0.0" errno@^0.1.3, errno@~0.1.7: @@ -1838,6 +2553,46 @@ errno@^0.1.3, errno@~0.1.7: dependencies: prr "~1.0.1" +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +error-stack-parser@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.6.tgz#5a99a707bd7a4c58a797902d48d82803ede6aad8" + integrity sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ== + dependencies: + stackframe "^1.1.1" + +es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@~0.10.46: + version "0.10.53" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" + integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.3" + next-tick "~1.0.0" + +es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -1868,15 +2623,25 @@ estraverse@^4.1.0, estraverse@^4.1.1: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -esutils@^2.0.2: +esutils@^2.0.0, esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +eventemitter2@4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-4.1.2.tgz#0e1a8477af821a6ef3995b311bf74c23a5247f15" + integrity sha1-DhqEd6+CGm7zmVsxG/dMI6UkfxU= + +events@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/events/-/events-2.1.0.tgz#2a9a1e18e6106e0e812aa9ebd4a819b3c29c0ba5" + integrity sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg== + events@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" - integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== + version "3.1.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" + integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" @@ -1924,6 +2689,13 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" +ext@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" + integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== + dependencies: + type "^2.0.0" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -1978,15 +2750,20 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-deep-equal@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" + integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-safe-stringify@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" + integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== fd-slicer@~1.0.1: version "1.0.1" @@ -2007,6 +2784,13 @@ figgy-pudding@^3.5.1: resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== +figures@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + figures@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" @@ -2015,6 +2799,11 @@ figures@^1.7.0: escape-string-regexp "^1.0.5" object-assign "^4.1.0" +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -2109,12 +2898,21 @@ fs-extra@5.0.0: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-minipass@^1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" - integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== dependencies: - minipass "^2.2.1" + minipass "^2.6.0" fs-write-stream-atomic@^1.0.8: version "1.0.10" @@ -2132,12 +2930,12 @@ fs.realpath@^1.0.0: integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^1.2.7: - version "1.2.9" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" - integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== + version "1.2.11" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.11.tgz#67bf57f4758f02ede88fb2a1712fef4d15358be3" + integrity sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw== dependencies: + bindings "^1.5.0" nan "^2.12.1" - node-pre-gyp "^0.12.0" function-bind@^1.1.1: version "1.1.1" @@ -2158,6 +2956,21 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + +get-assigned-identifiers@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz#6dbf411de648cbaf8d9169ebb0d2d576191e2ff1" + integrity sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ== + +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= + get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -2182,6 +2995,11 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" +gherkin@^5.0.0, gherkin@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/gherkin/-/gherkin-5.1.0.tgz#684bbb03add24eaf7bdf544f58033eb28fb3c6d5" + integrity sha1-aEu7A63STq9731RPWAM+so+zxtU= + glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -2190,10 +3008,10 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob@^7.1.3, glob@^7.1.4: - version "7.1.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== +glob@^7.0.0, glob@^7.1.0, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2215,9 +3033,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.2.2" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02" - integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q== + version "4.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" + integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== har-schema@^2.0.0: version "2.0.0" @@ -2245,9 +3063,9 @@ has-flag@^3.0.0: integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== has-unicode@^2.0.0: version "2.0.1" @@ -2285,6 +3103,13 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" +has@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + hash-base@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" @@ -2310,6 +3135,11 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +htmlescape@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" + integrity sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E= + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -2342,9 +3172,9 @@ iferr@^0.1.5: integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= ignore-walk@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.2.tgz#99d83a246c196ea5c93ef9315ad7b0819c35069b" - integrity sha512-EXyErtpHbn75ZTsOADsfx6J/FPo6/5cjev46PXrcTpd8z3BoRkXgYu9/JVqrI7tusjmwCZutGeRJeU0Wo1e4Cw== + version "3.0.3" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" + integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== dependencies: minimatch "^3.0.4" @@ -2360,7 +3190,7 @@ indent-string@^2.1.0: dependencies: repeating "^2.0.0" -indent-string@^3.0.0: +indent-string@^3.0.0, indent-string@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= @@ -2398,7 +3228,30 @@ ini@^1.3.4, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== -invariant@^2.2.2: +inline-source-map@~0.6.0: + version "0.6.2" + resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" + integrity sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU= + dependencies: + source-map "~0.5.3" + +insert-module-globals@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.2.0.tgz#ec87e5b42728479e327bd5c5c71611ddfb4752ba" + integrity sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw== + dependencies: + JSONStream "^1.0.3" + acorn-node "^1.5.2" + combine-source-map "^0.8.0" + concat-stream "^1.6.1" + is-buffer "^1.1.0" + path-is-absolute "^1.0.1" + process "~0.11.0" + through2 "^2.0.0" + undeclared-identifiers "^1.1.2" + xtend "^4.0.0" + +invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -2419,6 +3272,11 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" @@ -2426,7 +3284,7 @@ is-binary-path@^1.0.0: dependencies: binary-extensions "^1.0.0" -is-buffer@^1.1.5: +is-buffer@^1.1.0, is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -2470,6 +3328,11 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -2488,11 +3351,9 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= - dependencies: - number-is-nan "^1.0.0" + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" + integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== is-fullwidth-code-point@^1.0.0: version "1.0.0" @@ -2506,6 +3367,11 @@ is-fullwidth-code-point@^2.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= +is-generator@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-generator/-/is-generator-1.0.3.tgz#c14c21057ed36e328db80347966c693f886389f3" + integrity sha1-wUwhBX7TbjKNuANHlmxpP4hjifM= + is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" @@ -2611,10 +3477,10 @@ its-name@1.0.0: resolved "https://registry.yarnpkg.com/its-name/-/its-name-1.0.0.tgz#2065f1883ecb568c65f7112ddbf123401fae4af0" integrity sha1-IGXxiD7LVoxl9xEt2/EjQB+uSvA= -js-beautify@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.0.tgz#9753a13c858d96828658cd18ae3ca0e5783ea672" - integrity sha512-OMwf/tPDpE/BLlYKqZOhqWsd3/z2N3KOlyn1wsCRGFwViE8LOQTcDtathQvHvZc+q+zWmcNAbwKSC+iJoMaH2Q== +js-beautify@1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.3.tgz#c73fa10cf69d3dfa52d8ed624f23c64c0a6a94c1" + integrity sha512-wfk/IAWobz1TfApSdivH5PJ0miIHgDoYb1ugSqHcODPmaYu46rYe5FVuIEkhjg8IQiv6rDNPyhsqbsohI/C2vQ== dependencies: config-chain "^1.1.12" editorconfig "^0.15.3" @@ -2627,12 +3493,17 @@ js-levenshtein@^1.1.3: resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== +js-string-escape@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + integrity sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8= + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.1: +js-yaml@^3.13.1, js-yaml@^3.9.0: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -2655,7 +3526,7 @@ jsesc@~0.5.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= -json-parse-better-errors@^1.0.2: +json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== @@ -2670,6 +3541,13 @@ json-schema@0.2.3: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= +json-stable-stringify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" + integrity sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U= + dependencies: + jsonify "~0.0.0" + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -2683,9 +3561,9 @@ json5@^1.0.1: minimist "^1.2.0" json5@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" - integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== + version "2.1.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6" + integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ== dependencies: minimist "^1.2.0" @@ -2696,6 +3574,16 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -2726,15 +3614,42 @@ kind-of@^5.0.0: integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +knuth-shuffle-seeded@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz#01f1b65733aa7540ee08d8b0174164d22081e4e1" + integrity sha1-AfG2VzOqdUDuCNiwF0Fk0iCB5OE= + dependencies: + seed-random "~2.2.0" + +labeled-stream-splicer@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz#42a41a16abcd46fd046306cf4f2c3576fffb1c21" + integrity sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw== + dependencies: + inherits "^2.0.1" + stream-splicer "^2.0.0" lazy-ass@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" integrity sha1-eZllXoZGwX8In90YfRUNMyTVRRM= +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levenary@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" + integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== + dependencies: + leven "^3.1.0" + listr-silent-renderer@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" @@ -2808,12 +3723,22 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +lodash.clonedeep@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + +lodash.memoize@~3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" + integrity sha1-LcvSwofLwKVcxCMovQxzYVDVPj8= + lodash.once@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= -lodash@4.17.15, lodash@^4.17.10, lodash@^4.17.13: +lodash@4.17.15, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.4: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -2847,6 +3772,11 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= + lru-cache@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -2896,7 +3826,7 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" -memory-fs@^0.4.0, memory-fs@^0.4.1: +memory-fs@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= @@ -2904,6 +3834,14 @@ memory-fs@^0.4.0, memory-fs@^0.4.1: errno "^0.1.3" readable-stream "^2.0.1" +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -2939,17 +3877,17 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -mime-db@1.40.0: - version "1.40.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" - integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== +mime-db@1.43.0: + version "1.43.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" + integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.24" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" - integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== + version "2.1.26" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" + integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== dependencies: - mime-db "1.40.0" + mime-db "1.43.0" minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" @@ -2973,25 +3911,25 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@1.2.0, minimist@^1.2.0: +minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= -minipass@^2.2.1, minipass@^2.3.5: - version "2.5.1" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.5.1.tgz#cf435a9bf9408796ca3a3525a8b851464279c9b8" - integrity sha512-dmpSnLJtNQioZFI5HfQ55Ad0DzzsMAb+HfokwRTNXwEQjepbTkl5mtIlSVxGIkOkxlpX7wIn5ET/oAd9fZ/Y/Q== +minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== dependencies: safe-buffer "^5.1.2" yallist "^3.0.0" minizlib@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.2.tgz#6f0ccc82fa53e1bf2ff145f220d2da9fa6e3a166" - integrity sha512-hR3At21uSrsjjDTWrbu0IMLTpnkpv8IIMFDFaoz43Tmu4LkmAXfH44vNNzpTnf+OAQQCHrb91y/wc2J4x5XgSQ== + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== dependencies: - minipass "^2.2.1" + minipass "^2.9.0" mississippi@^3.0.0: version "3.0.0" @@ -3024,6 +3962,27 @@ mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: dependencies: minimist "0.0.8" +module-deps@^6.0.0: + version "6.2.2" + resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-6.2.2.tgz#d8a15c2265dfc119153c29bb47386987d0ee423b" + integrity sha512-a9y6yDv5u5I4A+IPHTnqFxcaKr4p50/zxTjcQJaX2ws9tN/W6J6YXnEKhqRyPhl494dkcxx951onSKVezmI+3w== + dependencies: + JSONStream "^1.0.3" + browser-resolve "^1.7.0" + cached-path-relative "^1.0.2" + concat-stream "~1.6.0" + defined "^1.0.0" + detective "^5.2.0" + duplexer2 "^0.1.2" + inherits "^2.0.1" + parents "^1.0.0" + readable-stream "^2.0.2" + resolve "^1.4.0" + stream-combiner2 "^1.1.1" + subarg "^1.0.0" + through2 "^2.0.0" + xtend "^4.0.0" + moment@2.24.0: version "2.24.0" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" @@ -3051,6 +4010,15 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +mz@^2.4.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + nan@^2.12.1: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" @@ -3074,9 +4042,9 @@ nanomatch@^1.2.9: to-regex "^3.0.1" needle@^2.2.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" - integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== + version "2.3.2" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.2.tgz#3342dea100b7160960a450dc8c22160ac712a528" + integrity sha512-DUzITvPVDUy6vczKKYTnWc/pBZ0EnjMJnQ3y+Jo5zfKFimJs7S3HFCxCRZYB9FUZcrzUQr3WsmvZgddMEIZv6w== dependencies: debug "^3.2.6" iconv-lite "^0.4.4" @@ -3087,11 +4055,23 @@ neo-async@^2.5.0, neo-async@^2.6.1: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== +next-tick@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== + dependencies: + lower-case "^1.1.1" + node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" @@ -3121,10 +4101,10 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-pre-gyp@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" - integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== +node-pre-gyp@*: + version "0.14.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" + integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== dependencies: detect-libc "^1.0.2" mkdirp "^0.5.1" @@ -3135,14 +4115,14 @@ node-pre-gyp@^0.12.0: rc "^1.2.7" rimraf "^2.6.1" semver "^5.3.0" - tar "^4" + tar "^4.4.2" -node-releases@^1.1.29: - version "1.1.30" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.30.tgz#35eebf129c63baeb6d8ddeda3c35b05abfd37f7f" - integrity sha512-BHcr1g6NeUH12IL+X3Flvs4IOnl1TL0JczUhEZjDE+FXXPQcVCNr8NEPb01zqGxzhTpdyJL5GXemaCW7aw6Khw== +node-releases@^1.1.47: + version "1.1.48" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.48.tgz#7f647f0c453a0495bcd64cbd4778c26035c2f03a" + integrity sha512-Hr8BbmUl1ujAST0K0snItzEA5zkJTQup8VNTKNfT6Zw8vTJkIiagUPNfxHmgDOyfFYNfKAul40sD0UEYTvwebw== dependencies: - semver "^5.3.0" + semver "^6.3.0" nopt@^4.0.1, nopt@~4.0.1: version "4.0.1" @@ -3165,17 +4145,25 @@ normalize-path@^3.0.0: integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== npm-bundled@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" - integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + version "1.1.1" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" + integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== + dependencies: + npm-normalize-package-bin "^1.0.1" + +npm-normalize-package-bin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== npm-packlist@^1.1.6: - version "1.4.4" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44" - integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw== + version "1.4.8" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" + integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== dependencies: ignore-walk "^3.0.1" npm-bundled "^1.0.1" + npm-normalize-package-bin "^1.0.1" npm-run-path@^2.0.0: version "2.0.2" @@ -3269,7 +4257,7 @@ ora@^0.2.3: cli-spinners "^0.1.2" object-assign "^4.0.1" -os-browserify@^0.3.0: +os-browserify@^0.3.0, os-browserify@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= @@ -3292,15 +4280,22 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +outpipe@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/outpipe/-/outpipe-1.1.1.tgz#50cf8616365e87e031e29a5ec9339a3da4725fa2" + integrity sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I= + dependencies: + shell-quote "^1.4.2" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= p-limit@^2.0.0, p-limit@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" - integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== + version "2.2.2" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" + integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== dependencies: p-try "^2.0.0" @@ -3321,10 +4316,17 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pad-right@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/pad-right/-/pad-right-0.2.2.tgz#6fbc924045d244f2a2a244503060d3bfc6009774" + integrity sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q= + dependencies: + repeat-string "^1.5.2" + pako@~1.0.5: - version "1.0.10" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" - integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== parallel-transform@^1.1.0: version "1.2.0" @@ -3335,10 +4337,17 @@ parallel-transform@^1.1.0: inherits "^2.0.3" readable-stream "^2.1.5" +parents@^1.0.0, parents@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" + integrity sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E= + dependencies: + path-platform "~0.11.15" + parse-asn1@^5.0.0: - version "5.1.4" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc" - integrity sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw== + version "5.1.5" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" + integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ== dependencies: asn1.js "^4.0.0" browserify-aes "^1.0.0" @@ -3347,12 +4356,20 @@ parse-asn1@^5.0.0: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= -path-browserify@0.0.1: +path-browserify@0.0.1, path-browserify@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== @@ -3367,7 +4384,7 @@ path-exists@^3.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= -path-is-absolute@^1.0.0: +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= @@ -3387,6 +4404,16 @@ path-parse@^1.0.6: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-platform@~0.11.15: + version "0.11.15" + resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" + integrity sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I= + +pathval@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= + pbkdf2@^3.0.3: version "3.0.17" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" @@ -3409,9 +4436,9 @@ performance-now@^2.1.0: integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= picomatch@^2.0.5: - version "2.0.7" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6" - integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== + version "2.2.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" + integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== pify@^2.2.0: version "2.3.0" @@ -3445,11 +4472,16 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -process@^0.11.10: +process@^0.11.10, process@~0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" @@ -3471,9 +4503,9 @@ pseudomap@^1.0.2: integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= psl@^1.1.24: - version "1.4.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.4.0.tgz#5dd26156cdb69fa1fdb8ab1991667d3f80ced7c2" - integrity sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw== + version "1.7.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c" + integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ== public-encrypt@^4.0.0: version "4.0.3" @@ -3517,7 +4549,7 @@ punycode@1.3.2: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= -punycode@^1.2.4, punycode@^1.4.1: +punycode@^1.2.4, punycode@^1.3.2, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= @@ -3532,7 +4564,7 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== -querystring-es3@^0.2.0: +querystring-es3@^0.2.0, querystring-es3@~0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= @@ -3577,10 +4609,17 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +read-only-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" + integrity sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A= + dependencies: + readable-stream "^2.0.2" + "readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -3590,6 +4629,15 @@ rc@^1.2.7: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@^3.0.6: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.5.0.tgz#465d70e6d1087f6162d079cd0b5db7fbebfd1606" + integrity sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -3611,6 +4659,16 @@ regenerate@^1.4.0: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== + regenerator-transform@^0.14.0: version "0.14.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" @@ -3626,12 +4684,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp-tree@^0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.13.tgz#5b19ab9377edc68bc3679256840bb29afc158d7f" - integrity sha512-hwdV/GQY5F8ReLZWO+W1SRoN5YfpOKY6852+tBFcma72DKBIcHjPRIlIvQN35bCOljuAfP2G2iB0FC/w236mUw== - -regexpu-core@^4.5.4: +regexpu-core@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6" integrity sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg== @@ -3644,14 +4697,14 @@ regexpu-core@^4.5.4: unicode-match-property-value-ecmascript "^1.1.0" regjsgen@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd" - integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA== + version "0.5.1" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" + integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== regjsparser@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" - integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ== + version "0.6.2" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.2.tgz#fd62c753991467d9d1ffe0a9f67f27a529024b96" + integrity sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q== dependencies: jsesc "~0.5.0" @@ -3665,7 +4718,7 @@ repeat-element@^1.1.2: resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== -repeat-string@^1.6.1: +repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= @@ -3710,15 +4763,25 @@ request@2.88.0: tunnel-agent "^0.6.0" uuid "^3.3.2" +require-from-string@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.3.2: - version "1.12.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" - integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= + +resolve@^1.1.4, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.8.1: + version "1.15.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" + integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== dependencies: path-parse "^1.0.6" @@ -3800,7 +4863,17 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: +seed-random@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/seed-random/-/seed-random-2.2.0.tgz#2a9b19e250a817099231a5b99a4daf80b7fbed54" + integrity sha1-KpsZ4lCoFwmSMaW5mk2vgLf77VQ= + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -3810,10 +4883,15 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -serialize-javascript@^1.7.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.9.1.tgz#cfc200aef77b600c47da9bb8149c943e798c2fdb" - integrity sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A== +serialize-error@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a" + integrity sha1-ULZ51WNc34Rme9yOWa9OW4HV9go= + +serialize-javascript@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" + integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== set-blocking@~2.0.0: version "2.0.0" @@ -3835,7 +4913,7 @@ setimmediate@^1.0.4: resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= -sha.js@^2.4.0, sha.js@^2.4.8: +sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4: version "2.4.11" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== @@ -3843,6 +4921,21 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +shasum-object@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shasum-object/-/shasum-object-1.0.0.tgz#0b7b74ff5b66ecf9035475522fa05090ac47e29e" + integrity sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg== + dependencies: + fast-safe-stringify "^2.0.7" + +shasum@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/shasum/-/shasum-1.0.2.tgz#e7012310d8f417f4deb5712150e5678b87ae565f" + integrity sha1-5wEjENj0F/TetXEhUOVni4euVl8= + dependencies: + json-stable-stringify "~0.0.0" + sha.js "~2.4.4" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -3855,6 +4948,11 @@ shebang-regex@^1.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= +shell-quote@^1.4.2, shell-quote@^1.6.1: + version "1.7.2" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" + integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + sigmund@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" @@ -3865,6 +4963,11 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +simple-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" + integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= + slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" @@ -3930,20 +5033,20 @@ source-list-map@^2.0.0: integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== dependencies: - atob "^2.1.1" + atob "^2.1.2" decode-uri-component "^0.2.0" resolve-url "^0.2.1" source-map-url "^0.4.0" urix "^0.1.0" source-map-support@~0.5.12: - version "0.5.13" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" - integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + version "0.5.16" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" + integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -3953,7 +5056,12 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@^0.5.0, source-map@^0.5.6: +source-map@0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= + +source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.3: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -3997,6 +5105,40 @@ ssri@^6.0.1: dependencies: figgy-pudding "^3.5.1" +stack-chain@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-2.0.0.tgz#d73d1172af89565f07438b5bcc086831b6689b2d" + integrity sha512-GGrHXePi305aW7XQweYZZwiRwR7Js3MWoK/EHzzB9ROdc75nCnjSJVi21rdAGxFl+yCx2L2qdfl5y7NO4lTyqg== + +stack-generator@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-generator/-/stack-generator-2.0.5.tgz#fb00e5b4ee97de603e0773ea78ce944d81596c36" + integrity sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q== + dependencies: + stackframe "^1.1.1" + +stackframe@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.1.1.tgz#ffef0a3318b1b60c3b58564989aca5660729ec71" + integrity sha512-0PlYhdKh6AfFxRyK/v+6/k+/mMfyiEBbTM5L94D0ZytQnJ166wuwoTYLHFWGbs2dpA8Rgq763KGWmN1EQEYHRQ== + +stacktrace-gps@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.0.4.tgz#7688dc2fc09ffb3a13165ebe0dbcaf41bcf0c69a" + integrity sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg== + dependencies: + source-map "0.5.6" + stackframe "^1.1.1" + +stacktrace-js@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stacktrace-js/-/stacktrace-js-2.0.2.tgz#4ca93ea9f494752d55709a081d400fdaebee897b" + integrity sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg== + dependencies: + error-stack-parser "^2.0.6" + stack-generator "^2.0.5" + stacktrace-gps "^3.0.4" + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -4005,7 +5147,7 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -stream-browserify@^2.0.1: +stream-browserify@^2.0.0, stream-browserify@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== @@ -4013,6 +5155,14 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" +stream-combiner2@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" + integrity sha1-+02KFCDqNidk4hrUeAOXvry0HL4= + dependencies: + duplexer2 "~0.1.0" + readable-stream "^2.0.2" + stream-each@^1.1.0: version "1.2.3" resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" @@ -4021,7 +5171,7 @@ stream-each@^1.1.0: end-of-stream "^1.1.0" stream-shift "^1.0.0" -stream-http@^2.7.2: +stream-http@^2.0.0, stream-http@^2.7.2: version "2.8.3" resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== @@ -4032,16 +5182,39 @@ stream-http@^2.7.2: to-arraybuffer "^1.0.0" xtend "^4.0.0" +stream-http@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.1.0.tgz#22fb33fe9b4056b4eccf58bd8f400c4b993ffe57" + integrity sha512-cuB6RgO7BqC4FBYzmnvhob5Do3wIdIsXAgGycHJnW+981gHqoYcYz9lqjJrk8WXRddbwPuqPYRl+bag6mYv4lw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^3.0.6" + xtend "^4.0.0" + stream-shift@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" - integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + +stream-splicer@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.1.tgz#0b13b7ee2b5ac7e0609a7463d83899589a363fcd" + integrity sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg== + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.2" stream-to-observable@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.1.0.tgz#45bf1d9f2d7dc09bed81f1c307c430e68b84cffe" integrity sha1-Rb8dny19wJvtgfHDB8Qw5ouEz/4= +string-argv@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.0.2.tgz#dac30408690c21f3c3630a3ff3a05877bdcbd736" + integrity sha1-2sMECGkMIfPDYwo/86BYd73L1zY= + string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -4059,7 +5232,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string_decoder@^1.0.0: +string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== @@ -4104,6 +5277,13 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +subarg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" + integrity sha1-9izxdYHplrSPyWVpn1TAauJouNI= + dependencies: + minimist "^1.1.0" + supports-color@5.5.0, supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -4121,48 +5301,69 @@ symbol-observable@1.0.1: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= +syntax-error@^1.1.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.4.0.tgz#2d9d4ff5c064acb711594a3e3b95054ad51d907c" + integrity sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w== + dependencies: + acorn-node "^1.2.0" + tapable@^1.0.0, tapable@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tar@^4: - version "4.4.10" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" - integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== +tar@^4.4.2: + version "4.4.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" + integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== dependencies: chownr "^1.1.1" fs-minipass "^1.2.5" - minipass "^2.3.5" + minipass "^2.8.6" minizlib "^1.2.1" mkdirp "^0.5.0" safe-buffer "^5.1.2" yallist "^3.0.3" -terser-webpack-plugin@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz#61b18e40eaee5be97e771cdbb10ed1280888c2b4" - integrity sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg== +terser-webpack-plugin@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" + integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== dependencies: cacache "^12.0.2" find-cache-dir "^2.1.0" is-wsl "^1.1.0" schema-utils "^1.0.0" - serialize-javascript "^1.7.0" + serialize-javascript "^2.1.2" source-map "^0.6.1" terser "^4.1.2" webpack-sources "^1.4.0" worker-farm "^1.7.0" terser@^4.1.2: - version "4.3.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.3.1.tgz#09820bcb3398299c4b48d9a86aefc65127d0ed65" - integrity sha512-pnzH6dnFEsR2aa2SJaKb1uSCl3QmIsJ8dEkj0Fky+2AwMMcC9doMqLOQIH6wVTEKaVfKVvLSk5qxPBEZT9mywg== + version "4.6.3" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87" + integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ== dependencies: commander "^2.20.0" source-map "~0.6.1" source-map-support "~0.5.12" +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.0" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839" + integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk= + dependencies: + any-promise "^1.0.0" + throttleit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" @@ -4176,6 +5377,18 @@ through2@^2.0.0: readable-stream "~2.3.6" xtend "~4.0.1" +"through@>=2.2.7 <3", through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +timers-browserify@^1.0.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" + integrity sha1-ycWLV1voQHN1y14kYtrO50NZ9B0= + dependencies: + process "~0.11.0" + timers-browserify@^2.0.4: version "2.0.11" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f" @@ -4183,6 +5396,14 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" +title-case@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa" + integrity sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o= + dependencies: + no-case "^2.2.0" + upper-case "^1.0.3" + tmp@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877" @@ -4240,15 +5461,10 @@ tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= - ts-loader@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.1.0.tgz#999cb0a7644f9c7c6c0901802dce50ceb0a76e5b" - integrity sha512-7JedeOu2rsYHQDEr2fwmMozABwbQTZXEaEMZPSIWG7gpzRefOLJCqwdazcegHtyaxp04PeEgs/b0m08WMpnIzQ== + version "6.2.1" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.2.1.tgz#67939d5772e8a8c6bdaf6277ca023a4812da02ef" + integrity sha512-Dd9FekWuABGgjE1g0TlQJ+4dFUfYGbYcs52/HQObE0ZmUNjQlmLAS7xXsSzy23AMaMwipsx5sNHvoEpT2CZq1g== dependencies: chalk "^2.3.0" enhanced-resolve "^4.0.0" @@ -4266,6 +5482,11 @@ tty-browserify@0.0.0: resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= +tty-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" + integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -4278,15 +5499,46 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +type-detect@^4.0.0, type-detect@^4.0.5: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3" + integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow== + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.6.3: - version "3.6.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.3.tgz#fea942fabb20f7e1ca7164ff626f1a9f3f70b4da" - integrity sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw== +typescript@3.7.5: + version "3.7.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" + integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== + +umd@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.3.tgz#aa9fe653c42b9097678489c01000acb69f0b26cf" + integrity sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow== + +undeclared-identifiers@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz#9254c1d37bdac0ac2b52de4b6722792d2a91e30f" + integrity sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw== + dependencies: + acorn-node "^1.3.0" + dash-ast "^1.0.0" + get-assigned-identifiers "^1.2.0" + simple-concat "^1.0.0" + xtend "^4.0.1" unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" @@ -4348,11 +5600,21 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" +untildify@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9" + integrity sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA== + upath@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== +upper-case@^1.0.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= + uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" @@ -4365,7 +5627,7 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url@0.11.0, url@^0.11.0: +url@0.11.0, url@^0.11.0, url@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= @@ -4378,7 +5640,12 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -util-deprecate@~1.0.1: +util-arity@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/util-arity/-/util-arity-1.1.0.tgz#59d01af1fdb3fede0ac4e632b0ab5f6ce97c9330" + integrity sha1-WdAa8f2z/t4KxOYysKtfbOl8kzA= + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= @@ -4397,10 +5664,17 @@ util@^0.11.0: dependencies: inherits "2.0.3" +util@~0.10.1: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + uuid@^3.3.2: - version "3.3.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" - integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== variable-diff@1.1.0: version "1.1.0" @@ -4410,7 +5684,7 @@ variable-diff@1.1.0: chalk "^1.1.1" object-assign "^4.0.1" -verror@1.10.0: +verror@1.10.0, verror@^1.9.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= @@ -4419,10 +5693,23 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vm-browserify@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019" - integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw== +vm-browserify@^1.0.0, vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +watchify@3.11.1: + version "3.11.1" + resolved "https://registry.yarnpkg.com/watchify/-/watchify-3.11.1.tgz#8e4665871fff1ef64c0430d1a2c9d084d9721881" + integrity sha512-WwnUClyFNRMB2NIiHgJU9RQPQNqVeFk7OmZaWf5dC5EnNa0Mgr7imBydbaJ7tGTuPM2hz1Cb4uiBvK9NVxMfog== + dependencies: + anymatch "^2.0.0" + browserify "^16.1.0" + chokidar "^2.1.1" + defined "^1.0.0" + outpipe "^1.1.0" + through2 "^2.0.0" + xtend "^4.0.0" watchpack@^1.6.0: version "1.6.0" @@ -4442,9 +5729,9 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1: source-map "~0.6.1" webpack@^4.40.2: - version "4.40.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.40.2.tgz#d21433d250f900bf0facbabe8f50d585b2dc30a7" - integrity sha512-5nIvteTDCUws2DVvP9Qe+JPla7kWPPIDFZv55To7IycHWZ+Z5qBdaBYPyuXWdhggTufZkQwfIK+5rKQTVovm2A== + version "4.41.5" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.5.tgz#3210f1886bce5310e62bb97204d18c263341b77c" + integrity sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw== dependencies: "@webassemblyjs/ast" "1.8.5" "@webassemblyjs/helper-module-context" "1.8.5" @@ -4466,7 +5753,7 @@ webpack@^4.40.2: node-libs-browser "^2.2.1" schema-utils "^1.0.0" tapable "^1.1.3" - terser-webpack-plugin "^1.4.1" + terser-webpack-plugin "^1.4.3" watchpack "^1.6.0" webpack-sources "^1.4.1" @@ -4496,7 +5783,7 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xtend@^4.0.0, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== @@ -4512,9 +5799,9 @@ yallist@^2.1.2: integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" - integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yauzl@2.10.0: version "2.10.0" diff --git a/x-pack/tsconfig.json b/x-pack/tsconfig.json index 723da7cef6a77..31ef0bef18a85 100644 --- a/x-pack/tsconfig.json +++ b/x-pack/tsconfig.json @@ -12,7 +12,7 @@ "exclude": [ "test/**/*", "legacy/plugins/siem/cypress/**/*", - "legacy/plugins/apm/cypress/**/*", + "legacy/plugins/apm/e2e/cypress/**/*", "**/typespec_tests.ts" ], "compilerOptions": { From 07fec2f7251e6b2fe0ed30ce9d08f1133416806e Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Wed, 26 Feb 2020 14:17:59 -0500 Subject: [PATCH 102/123] Documentation for numeral pattern formatting (#57616) * Documentation for Elastic Numeral formatting * Tweaks from feedback * Updates from feedback * Fix and update examples * Add TODOs * Fix typo Co-authored-by: Elastic Machine --- .../canvas/canvas-function-reference.asciidoc | 6 +- docs/management/advanced-options.asciidoc | 10 +- docs/management/managing-fields.asciidoc | 6 +- docs/management/numeral.asciidoc | 184 ++++++++++++++++++ docs/user/management.asciidoc | 2 + package.json | 2 +- .../legacy/plugins/canvas/i18n/constants.ts | 2 +- .../i18n/functions/dict/formatnumber.ts | 8 +- .../canvas/i18n/functions/dict/metric.ts | 5 +- .../canvas/public/lib/documentation_links.ts | 3 + x-pack/package.json | 2 +- .../translations/translations/ja-JP.json | 3 - .../translations/translations/zh-CN.json | 3 - yarn.lock | 13 +- 14 files changed, 212 insertions(+), 37 deletions(-) create mode 100644 docs/management/numeral.asciidoc diff --git a/docs/canvas/canvas-function-reference.asciidoc b/docs/canvas/canvas-function-reference.asciidoc index 330cc63d10548..85e9d22490497 100644 --- a/docs/canvas/canvas-function-reference.asciidoc +++ b/docs/canvas/canvas-function-reference.asciidoc @@ -1244,7 +1244,7 @@ Alias: `format` [[formatnumber_fn]] === `formatnumber` -Formats a number into a formatted number string using NumeralJS. For more information, see http://numeraljs.com/#format. +Formats a number into a formatted number string using the <>. *Expression syntax* [source,js] @@ -1276,7 +1276,7 @@ The `formatnumber` subexpression receives the same `context` as the `progress` f Alias: `format` |`string` -|A NumeralJS format string. For example, `"0.0a"` or `"0%"`. See http://numeraljs.com/#format. +|A <> string. For example, `"0.0a"` or `"0%"`. |=== *Returns:* `string` @@ -1675,7 +1675,7 @@ Default: `${font size=48 family="'Open Sans', Helvetica, Arial, sans-serif" colo Alias: `format` |`string` -|A NumeralJS format string. For example, `"0.0a"` or `"0%"`. See http://numeraljs.com/#format. +|A <> string. For example, `"0.0a"` or `"0%"`. |=== *Returns:* `render` diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 9d4052bbd0156..c698e2db86ddb 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -51,13 +51,13 @@ adapt to the interval between measurements. Keys are http://en.wikipedia.org/wik `fields:popularLimit`:: The top N most popular fields to show. `filterEditor:suggestValues`:: Set this property to `false` to prevent the filter editor from suggesting values for fields. `filters:pinnedByDefault`:: Set this property to `true` to make filters have a global state (be pinned) by default. -`format:bytes:defaultPattern`:: The default http://numeraljs.com/[numeral format] for the "bytes" format. -`format:currency:defaultPattern`:: The default http://numeraljs.com/[numeral format] for the "currency" format. +`format:bytes:defaultPattern`:: The default <> format for the "bytes" format. +`format:currency:defaultPattern`:: The default <> format for the "currency" format. `format:defaultTypeMap`:: A map of the default format name for each field type. Field types that are not explicitly mentioned use "\_default_". -`format:number:defaultLocale`:: The http://numeraljs.com/[numeral language] locale. -`format:number:defaultPattern`:: The default http://numeraljs.com/[numeral format] for the "number" format. -`format:percent:defaultPattern`:: The default http://numeraljs.com/[numeral format] for the "percent" format. +`format:number:defaultLocale`:: The <> locale. +`format:number:defaultPattern`:: The <> for the "number" format. +`format:percent:defaultPattern`:: The <> for the "percent" format. `histogram:barTarget`:: When date histograms use the `auto` interval, Kibana attempts to generate this number of bars. `histogram:maxBars`:: Date histograms are not generated with more bars than the value of this property, scaling values when necessary. diff --git a/docs/management/managing-fields.asciidoc b/docs/management/managing-fields.asciidoc index f66976b3715d1..b54f4fe5194ad 100644 --- a/docs/management/managing-fields.asciidoc +++ b/docs/management/managing-fields.asciidoc @@ -92,6 +92,9 @@ include::field-formatters/string-formatter.asciidoc[] Numeric fields support the `Url`, `Bytes`, `Duration`, `Number`, `Percentage`, `String`, and `Color` formatters. +The `Bytes`, `Number`, and `Percentage` formatters enable you to choose the display formats of numbers in this field using +the <> syntax that Kibana maintains. + include::field-formatters/url-formatter.asciidoc[] include::field-formatters/string-formatter.asciidoc[] @@ -100,9 +103,6 @@ include::field-formatters/duration-formatter.asciidoc[] include::field-formatters/color-formatter.asciidoc[] -The `Bytes`, `Number`, and `Percentage` formatters enable you to choose the display formats of numbers in this field using -the https://adamwdraper.github.io/Numeral-js/[numeral.js] standard format definitions. - [[scripted-fields]] === Scripted Fields diff --git a/docs/management/numeral.asciidoc b/docs/management/numeral.asciidoc new file mode 100644 index 0000000000000..861277fd18478 --- /dev/null +++ b/docs/management/numeral.asciidoc @@ -0,0 +1,184 @@ +[[numeral]] +== Numeral Formatting + +Numeral formatting in {kib} is done through a pattern-based syntax. +These patterns express common number formats in a concise way, similar +to date formatting. While these patterns are originally based on Numeral.js, +they are now maintained by {kib}. + +Numeral formatting patterns are used in multiple places in {kib}, including: + +* <> +* <> +* <> +* <> + +The simplest pattern format is `0`, and the default {kib} pattern is `0,0.[000]`. +The numeral pattern syntax expresses: + +Number of decimal places:: The `.` character turns on the option to show decimal +places using a locale-specific decimal separator, most often `.` or `,`. +To add trailing zeroes such as `5.00`, use a pattern like `0.00`. +To have optional zeroes, use the `[]` characters. Examples below. +Thousands separator:: The thousands separator `,` turns on the option to group +thousands using a locale-specific separator. The separator is most often `,` or `.`, +and sometimes ` `. +Accounting notation:: Putting parentheses around your format like `(0.00)` will use accounting notation to show negative numbers. + +The display of these patterns is affected by the <> `format:number:defaultLocale`. +The default locale is `en`, but some examples will specify that they are using an alternate locale. + +Most basic examples: + +|=== +| **Input** | **Pattern** | **Locale** | **Output** +| 10000.23 | 0,0 | en (English) | 10,000 +| 10000.23 | 0.0 | en (English) | 10000.2 +| 10000.23 | 0,0.0 | fr (French) | 10 000,2 +| 10000.23 | 0,0.000 | fr (French) | 10 000,230 +| 10000.23 | 0,0[.]0 | en (English) | 10,000.2 +| 10000.23 | 0.00[0] | en (English) | 10,000.23 +| -10000.23 | (0) | en (English) | (10000) +|=== + +[float] +=== Percentages + +By adding the `%` symbol to any of the previous patterns, the value +is multiplied by 100 and the `%` symbol is added in the place indicated. + +The default percentage formatter in {kib} is `0,0.[000]%`, which shows +up to three decimal places. + +|=== +| **Input** | **Pattern** | **Locale** | **Output** +| 0.43 | 0,0.[000]% | en (English) | 43.00% +| 0.43 | 0,0.[000]% | fr (French) | 43,00% +| 1 | 0% | en (English) | 100% +| -0.43 | 0 % | en (English) | -43 % +|=== + +[float] +=== Bytes and bits + +The bytes and bits formatters will shorten the input by adding a suffix like `GB` or `TB`. Bytes and bits formatters include the following suffixes: + +`b`:: Bytes with binary values and suffixes. 1024 = `1KB` +`bb`:: Bytes with binary values and binary suffixes. 1024 = `1KiB` +`bd`:: Bytes with decimal values and suffixes. 1000 = `1kB` +`bitb`:: Bits with binary values and suffixes. 1024 = `1Kibit` +`bitd`:: Bits with decimal values and suffixes. 1000 = `1kbit` + +Suffixes are not localized with this formatter. + +|=== +| **Input** | **Pattern** | **Locale** | **Output** +| 2000 | 0.00b | en (English) | 1.95KB +| 2000 | 0.00bb | en (English) | 1.95KiB +| 2000 | 0.00bd | en (English) | 2.00kB +| 3153654400000 | 0.00bd | en (English) | 3.15GB +| 2000 | 0.00bitb | en (English) | 1.95Kibit +| 2000 | 0.00bitd | en (English) | 2.00kbit +|=== + +[float] +=== Currency + +Currency formatting is limited in {kib} due to the limitations of the pattern +syntax. To enable currency formatting, use the symbol `$` in the pattern syntax. +The number formatting locale will affect the result. + +|=== +| **Input** | **Pattern** | **Locale** | **Output** +| 1000.234 | $0,0.00 | en (English) | $1,000.23 +| 1000.234 | $0,0.00 | fr (French) | €1 000,23 +| 1000.234 | $0,0.00 | chs (Simplified Chinese) | ¥1,000.23 +|=== + +[float] +=== Duration formatting + +Converts a value in seconds to display hours, minutes, and seconds. + +|=== +| **Input** | **Pattern** | **Output** +| 25 | 00:00:00 | 0:00:25 +| 25 | 00:00 | 0:00:25 +| 238 | 00:00:00 | 0:03:58 +| 63846 | 00:00:00 | 17:44:06 +| -1 | 00:00:00 | -0:00:01 +|=== + +[float] +=== Displaying abbreviated numbers + +The `a` pattern will look for the shortest abbreviation for your +number, and use a locale-specific display for it. The abbreviations +`aK`, `aM`, `aB`, and `aT` can indicate that the number should be +abbreviated to a specific order of magnitude. + +|=== +| **Input** | **Pattern** | **Locale** | **Output** +| 2000000000 | 0.00a | en (English) | 2.00b +| 2000000000 | 0.00a | ja (Japanese) | 2.00十億 +| -5444333222111 | 0,0 aK | en (English) | -5,444,333,222 k +| -5444333222111 | 0,0 aM | en (English) | -5,444,333 m +| -5444333222111 | 0,0 aB | en (English) | -5,444 b +| -5444333222111 | 0,0 aT | en (English) | -5 t +|=== + +[float] +=== Ordinal numbers + +The `o` pattern will display a locale-specific positional value like `1st` or `2nd`. +This pattern has limited support for localization, especially in languages +with multiple forms, such as German. + +|=== +| **Input** | **Pattern** | **Locale** | **Output** +| 3 | 0o | en (English) | 3rd +| 34 | 0o | en (English) | 34th +| 3 | 0o | es (Spanish) | 2er +| 3 | 0o | ru (Russian) | 3. +|=== + +[float] +=== Complete number pattern reference + +These number formats, combined with the patterns described above, +produce the complete set of options for numeral formatting. +The output here is all for the `en` locale. + +|=== +| **Input** | **Pattern** | **Output** +| 10000 | 0,0.0000 | 10,000.0000 +| 10000.23 | 0,0 | 10,000 +| -10000 | 0,0.0 | -10,000.0 +| 10000.1234 | 0.000 | 10000.123 +| 10000 | 0[.]00 | 10000 +| 10000.1 | 0[.]00 | 10000.10 +| 10000.123 | 0[.]00 | 10000.12 +| 10000.456 | 0[.]00 | 10000.46 +| 10000.001 | 0[.]00 | 10000 +| 10000.45 | 0[.]00[0] | 10000.45 +| 10000.456 | 0[.]00[0] | 10000.456 +| -10000 | (0,0.0000) | (10,000.0000) +| -12300 | +0,0.0000 | -12,300.0000 +| 1230 | +0,0 | +1,230 +| 100.78 | 0 | 101 +| 100.28 | 0 | 100 +| 1.932 | 0.0 | 1.9 +| 1.9687 | 0 | 2 +| 1.9687 | 0.0 | 2.0 +| -0.23 | .00 | -.23 +| -0.23 | (.00) | (.23) +| 0.23 | 0.00000 | 0.23000 +| 0.67 | 0.0[0000] | 0.67 +| 1.005 | 0.00 | 1.01 +| 1e35 | 000 | 1e+35 +| -1e35 | 000 | -1e+35 +| 1e-27 | 000 | 1e-27 +| -1e-27 | 000 | -1e-27 +|=== + + diff --git a/docs/user/management.asciidoc b/docs/user/management.asciidoc index 1c55ffc73ca72..34a3790529ca3 100644 --- a/docs/user/management.asciidoc +++ b/docs/user/management.asciidoc @@ -129,6 +129,8 @@ include::{kib-repo-dir}/management/managing-fields.asciidoc[] include::{kib-repo-dir}/management/managing-licenses.asciidoc[] +include::{kib-repo-dir}/management/numeral.asciidoc[] + include::{kib-repo-dir}/management/managing-remote-clusters.asciidoc[] include::{kib-repo-dir}/management/rollups/create_and_manage_rollups.asciidoc[] diff --git a/package.json b/package.json index c3fe290e7934f..0f04a2fba3b65 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,7 @@ "@elastic/eui": "19.0.0", "@elastic/filesaver": "1.1.2", "@elastic/good": "8.1.1-kibana2", - "@elastic/numeral": "2.3.5", + "@elastic/numeral": "2.4.0", "@elastic/request-crypto": "^1.0.2", "@elastic/ui-ace": "0.2.3", "@hapi/wreck": "^15.0.1", diff --git a/x-pack/legacy/plugins/canvas/i18n/constants.ts b/x-pack/legacy/plugins/canvas/i18n/constants.ts index 8aee6ca148681..4cb05b0426fa1 100644 --- a/x-pack/legacy/plugins/canvas/i18n/constants.ts +++ b/x-pack/legacy/plugins/canvas/i18n/constants.ts @@ -28,7 +28,7 @@ export const LUCENE = 'Lucene'; export const MARKDOWN = 'Markdown'; export const MOMENTJS = 'MomentJS'; export const MOMENTJS_TIMEZONE_URL = 'https://momentjs.com/timezone/'; -export const NUMERALJS = 'NumeralJS'; +export const NUMERALJS = 'Numeral pattern'; export const PDF = 'PDF'; export const POST = 'POST'; export const RGB = 'RGB'; diff --git a/x-pack/legacy/plugins/canvas/i18n/functions/dict/formatnumber.ts b/x-pack/legacy/plugins/canvas/i18n/functions/dict/formatnumber.ts index df306eb1c04ed..f3e8a8858fc36 100644 --- a/x-pack/legacy/plugins/canvas/i18n/functions/dict/formatnumber.ts +++ b/x-pack/legacy/plugins/canvas/i18n/functions/dict/formatnumber.ts @@ -12,21 +12,19 @@ import { NUMERALJS } from '../../constants'; export const help: FunctionHelp> = { help: i18n.translate('xpack.canvas.functions.formatnumberHelpText', { - defaultMessage: 'Formats a number into a formatted number string using {NUMERALJS}. See {url}.', + defaultMessage: 'Formats a number into a formatted number string using {NUMERALJS}.', values: { NUMERALJS, - url: 'http://numeraljs.com/#format', }, }), args: { + // TODO: Find a way to generate the docs URL here format: i18n.translate('xpack.canvas.functions.formatnumber.args.formatHelpText', { - defaultMessage: - 'A {NUMERALJS} format string. For example, {example1} or {example2}. See {url}.', + defaultMessage: 'A {NUMERALJS} format string. For example, {example1} or {example2}.', values: { example1: `"0.0a"`, example2: `"0%"`, NUMERALJS, - url: 'http://numeraljs.com/#format', }, }), }, diff --git a/x-pack/legacy/plugins/canvas/i18n/functions/dict/metric.ts b/x-pack/legacy/plugins/canvas/i18n/functions/dict/metric.ts index 8fa98667212a5..8258226e5dfc3 100644 --- a/x-pack/legacy/plugins/canvas/i18n/functions/dict/metric.ts +++ b/x-pack/legacy/plugins/canvas/i18n/functions/dict/metric.ts @@ -36,14 +36,13 @@ export const help: FunctionHelp> = { FONT_WEIGHT, }, }), + // TODO: Find a way to generate the docs URL here metricFormat: i18n.translate('xpack.canvas.functions.metric.args.metricFormatHelpText', { - defaultMessage: - 'A {NUMERALJS} format string. For example, {example1} or {example2}. See {url}.', + defaultMessage: 'A {NUMERALJS} format string. For example, {example1} or {example2}.', values: { example1: `"0.0a"`, example2: `"0%"`, NUMERALJS, - url: 'http://numeraljs.com/#format', }, }), }, diff --git a/x-pack/legacy/plugins/canvas/public/lib/documentation_links.ts b/x-pack/legacy/plugins/canvas/public/lib/documentation_links.ts index a43653f420ce0..40e09ee39d714 100644 --- a/x-pack/legacy/plugins/canvas/public/lib/documentation_links.ts +++ b/x-pack/legacy/plugins/canvas/public/lib/documentation_links.ts @@ -10,4 +10,7 @@ export const getDocumentationLinks = () => ({ canvas: `${getCoreStart().docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${ getCoreStart().docLinks.DOC_LINK_VERSION }/canvas.html`, + numeral: `${getCoreStart().docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${ + getCoreStart().docLinks.DOC_LINK_VERSION + }/guide/numeral.html`, }); diff --git a/x-pack/package.json b/x-pack/package.json index b8fe0326903b6..96e06dd71b3fe 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -183,7 +183,7 @@ "@elastic/filesaver": "1.1.2", "@elastic/maki": "6.1.0", "@elastic/node-crypto": "^1.0.0", - "@elastic/numeral": "2.3.3", + "@elastic/numeral": "2.4.0", "@kbn/babel-preset": "1.0.0", "@kbn/config-schema": "1.0.0", "@kbn/i18n": "1.0.0", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 3c7d0ce47acb7..b99a54160bb65 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4586,8 +4586,6 @@ "xpack.canvas.functions.filtersHelpText": "ワークパッドのエレメントフィルターを他 (通常データソース) で使用できるように集約します。", "xpack.canvas.functions.formatdate.args.formatHelpText": "{MOMENTJS} フォーマットです。例: {example}。{url} を参照。", "xpack.canvas.functions.formatdateHelpText": "{MOMENTJS} を使って {ISO8601} 日付文字列、または新世紀からのミリ秒での日付をフォーマットします。{url} を参照。", - "xpack.canvas.functions.formatnumber.args.formatHelpText": "{NUMERALJS} 文字列のフォーマットです。例: {example1} または {example2}。{url} を参照。", - "xpack.canvas.functions.formatnumberHelpText": "{NUMERALJS} を使って数字をフォーマットされた数字文字列にフォーマットします。{url} を参照。", "xpack.canvas.functions.getCell.args.columnHelpText": "値を取得する元の列の名前です。この値は入力されていないと、初めの列から取得されます。", "xpack.canvas.functions.getCell.args.rowHelpText": "行番号で、0 から開始します。", "xpack.canvas.functions.getCell.columnNotFoundErrorMessage": "列が見つかりません: 「{column}」", @@ -4633,7 +4631,6 @@ "xpack.canvas.functions.metric.args.labelFontHelpText": "ラベルの {CSS} フォントプロパティです。例: {FONT_FAMILY} または {FONT_WEIGHT}。", "xpack.canvas.functions.metric.args.labelHelpText": "メトリックを説明するテキストです。", "xpack.canvas.functions.metric.args.metricFontHelpText": "メトリックの {CSS} フォントプロパティです。例: {FONT_FAMILY} または {FONT_WEIGHT}。", - "xpack.canvas.functions.metric.args.metricFormatHelpText": "{NUMERALJS} 文字列のフォーマットです。例: {example1} または {example2}。{url} を参照。", "xpack.canvas.functions.metricHelpText": "ラベルの上に数字を表示します。", "xpack.canvas.functions.neq.args.valueHelpText": "{CONTEXT} と比較される値です。", "xpack.canvas.functions.neqHelpText": "{CONTEXT} が引数と等しくないかを戻します。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b262be626aa53..32f648826da84 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -4587,8 +4587,6 @@ "xpack.canvas.functions.filtersHelpText": "聚合 Workpad 的元素筛选以用于他处,通常用于数据源。", "xpack.canvas.functions.formatdate.args.formatHelpText": "{MOMENTJS} 格式。例如:{example}。请参见 {url}。", "xpack.canvas.functions.formatdateHelpText": "使用 {MOMENTJS} 格式化 {ISO8601} 日期字符串或自 Epoch 起以毫秒表示的日期。请参见 {url}。", - "xpack.canvas.functions.formatnumber.args.formatHelpText": "{NUMERALJS} 格式字符串。例如 {example1} 或 {example2}。请参见 {url}。", - "xpack.canvas.functions.formatnumberHelpText": "使用 {NUMERALJS} 将数字格式化为带格式数字字符串。请参见 {url}。", "xpack.canvas.functions.getCell.args.columnHelpText": "从其中提取值的列的名称。如果未提供,将从第一列检索值。", "xpack.canvas.functions.getCell.args.rowHelpText": "行编号,从 0 开始。", "xpack.canvas.functions.getCell.columnNotFoundErrorMessage": "找不到列:“{column}”", @@ -4634,7 +4632,6 @@ "xpack.canvas.functions.metric.args.labelFontHelpText": "标签的 {CSS} 字体属性。例如 {FONT_FAMILY} 或 {FONT_WEIGHT}。", "xpack.canvas.functions.metric.args.labelHelpText": "描述指标的文本。", "xpack.canvas.functions.metric.args.metricFontHelpText": "指标的 {CSS} 字体属性。例如 {FONT_FAMILY} 或 {FONT_WEIGHT}。", - "xpack.canvas.functions.metric.args.metricFormatHelpText": "{NUMERALJS} 格式字符串。例如 {example1} 或 {example2}。请参见 {url}。", "xpack.canvas.functions.metricHelpText": "在标签上显示数字。", "xpack.canvas.functions.neq.args.valueHelpText": "与 {CONTEXT} 比较的值。", "xpack.canvas.functions.neqHelpText": "返回 {CONTEXT} 是否不等于参数。", diff --git a/yarn.lock b/yarn.lock index 7906f363813b8..7f38495c20f4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2037,15 +2037,10 @@ resolved "https://registry.yarnpkg.com/@elastic/node-crypto/-/node-crypto-1.0.0.tgz#4d325df333fe1319556bb4d54214098ada1171d4" integrity sha512-bbjbEyILPRTRt0xnda18OttLtlkJBPuXx3CjISUSn9jhWqHoFMzfOaZ73D5jxZE2SaFZUrJYfPpqXP6qqPufAQ== -"@elastic/numeral@2.3.3": - version "2.3.3" - resolved "https://registry.yarnpkg.com/@elastic/numeral/-/numeral-2.3.3.tgz#94d38a35bd315efa7a6918b22695128fc40a885e" - integrity sha512-0OyB9oztlYIq8F1LHjcNf+T089PKfYw78tgUY+q2dtox/jmb4xzFKtI9kv1hwAt5tcgBUTtUMK9kszpSh1UZaQ== - -"@elastic/numeral@2.3.5": - version "2.3.5" - resolved "https://registry.yarnpkg.com/@elastic/numeral/-/numeral-2.3.5.tgz#fcaeac57ddc55cd4b7f0b9c7e070c242dd5d0600" - integrity sha512-lJVZHPuI2csrfwDIEdKedFqNIF+5YsyqvX2soAqhu49iKOd9n7tifLRn30vP6D7oKd+6HsiGfPzT0nzdJWsexQ== +"@elastic/numeral@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@elastic/numeral/-/numeral-2.4.0.tgz#883197b7f4bf3c2dd994f53b274769ddfa2bf79a" + integrity sha512-uGBKGCNghTgUZPHClji/00v+AKt5nidPTGOIbcT+lbTPVxNB6QPpPLGWtXyrg3QZAxobPM/LAZB1mAqtJeq44Q== "@elastic/request-crypto@^1.0.2": version "1.0.2" From 68624da3d57abf191ab1a52b004fbd8bef6fc38f Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 26 Feb 2020 14:34:44 -0500 Subject: [PATCH 103/123] [Maps] Add XYZTMSSource and TileLayer unit test suites (#58567) --- .../legacy/plugins/maps/common/constants.ts | 2 +- .../plugins/maps/common/descriptor_types.d.ts | 7 ++- .../plugins/maps/public/layers/layer.d.ts | 21 +++++++ .../maps/public/layers/sources/source.d.ts | 19 +++++++ .../public/layers/sources/tms_source.d.ts | 15 +++++ .../public/layers/sources/xyz_tms_source.d.ts | 11 ++++ .../public/layers/sources/xyz_tms_source.js | 3 +- .../layers/sources/xyz_tms_source.test.ts | 30 ++++++++++ .../maps/public/layers/tile_layer.d.ts | 18 ++++++ .../maps/public/layers/tile_layer.test.ts | 55 +++++++++++++++++++ 10 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 x-pack/legacy/plugins/maps/public/layers/layer.d.ts create mode 100644 x-pack/legacy/plugins/maps/public/layers/sources/source.d.ts create mode 100644 x-pack/legacy/plugins/maps/public/layers/sources/tms_source.d.ts create mode 100644 x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.d.ts create mode 100644 x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.test.ts create mode 100644 x-pack/legacy/plugins/maps/public/layers/tile_layer.d.ts create mode 100644 x-pack/legacy/plugins/maps/public/layers/tile_layer.test.ts diff --git a/x-pack/legacy/plugins/maps/common/constants.ts b/x-pack/legacy/plugins/maps/common/constants.ts index 542abfb004d0d..0e93fd6593710 100644 --- a/x-pack/legacy/plugins/maps/common/constants.ts +++ b/x-pack/legacy/plugins/maps/common/constants.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ import { i18n } from '@kbn/i18n'; - export const EMS_CATALOGUE_PATH = 'ems/catalogue'; export const EMS_FILES_CATALOGUE_PATH = 'ems/files'; @@ -54,6 +53,7 @@ export const EMS_FILE = 'EMS_FILE'; export const ES_GEO_GRID = 'ES_GEO_GRID'; export const ES_SEARCH = 'ES_SEARCH'; export const ES_PEW_PEW = 'ES_PEW_PEW'; +export const EMS_XYZ = 'EMS_XYZ'; // identifies a custom TMS source. Name is a little unfortunate. export const FIELD_ORIGIN = { SOURCE: 'source', diff --git a/x-pack/legacy/plugins/maps/common/descriptor_types.d.ts b/x-pack/legacy/plugins/maps/common/descriptor_types.d.ts index 05123c9c86b63..c024721dfb870 100644 --- a/x-pack/legacy/plugins/maps/common/descriptor_types.d.ts +++ b/x-pack/legacy/plugins/maps/common/descriptor_types.d.ts @@ -4,14 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IFieldType } from '../../../../../src/plugins/data/common/index_patterns/fields'; - export interface ISourceDescriptor { id: string; type: string; } +export interface IXYZTMSSourceDescriptor extends ISourceDescriptor { + urlTemplate: string; +} + export interface ILayerDescriptor { sourceDescriptor: ISourceDescriptor; id: string; + label?: string; } diff --git a/x-pack/legacy/plugins/maps/public/layers/layer.d.ts b/x-pack/legacy/plugins/maps/public/layers/layer.d.ts new file mode 100644 index 0000000000000..ed7dcb062d8c4 --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/layer.d.ts @@ -0,0 +1,21 @@ +/* + * 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 { ILayerDescriptor } from '../../common/descriptor_types'; +import { ISource } from './sources/source'; + +export interface ILayer { + getDisplayName(): Promise; +} + +export interface ILayerArguments { + layerDescriptor: ILayerDescriptor; + source: ISource; +} + +export class AbstractLayer implements ILayer { + constructor(layerArguments: ILayerArguments); + getDisplayName(): Promise; +} diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/source.d.ts b/x-pack/legacy/plugins/maps/public/layers/sources/source.d.ts new file mode 100644 index 0000000000000..372981de42597 --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/sources/source.d.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ISourceDescriptor } from '../../../common/descriptor_types'; +import { ILayer } from '../layer'; + +export interface ISource { + createDefaultLayer(): ILayer; + getDisplayName(): Promise; +} + +export class AbstractSource implements ISource { + constructor(sourceDescriptor: ISourceDescriptor, inspectorAdapters: object); + createDefaultLayer(): ILayer; + getDisplayName(): Promise; +} diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/tms_source.d.ts b/x-pack/legacy/plugins/maps/public/layers/sources/tms_source.d.ts new file mode 100644 index 0000000000000..90b6f28e050fd --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/sources/tms_source.d.ts @@ -0,0 +1,15 @@ +/* + * 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 { AbstractSource, ISource } from './source'; + +export interface ITMSSource extends ISource { + getUrlTemplate(): Promise; +} + +export class AbstractTMSSource extends AbstractSource implements ITMSSource { + getUrlTemplate(): Promise; +} diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.d.ts b/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.d.ts new file mode 100644 index 0000000000000..1150c39b79db5 --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.d.ts @@ -0,0 +1,11 @@ +/* + * 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 { AbstractTMSSource } from './tms_source'; +import { IXYZTMSSourceDescriptor } from '../../../common/descriptor_types'; + +export class XYZTMSSource extends AbstractTMSSource { + constructor(sourceDescriptor: IXYZTMSSourceDescriptor, inspectorAdapters: unknown); +} diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.js index a4d331f48beae..354883372e244 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.js @@ -12,9 +12,10 @@ import { TileLayer } from '../tile_layer'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel, getUrlLabel } from '../../../common/i18n_getters'; import _ from 'lodash'; +import { EMS_XYZ } from '../../../common/constants'; export class XYZTMSSource extends AbstractTMSSource { - static type = 'EMS_XYZ'; + static type = EMS_XYZ; static title = i18n.translate('xpack.maps.source.ems_xyzTitle', { defaultMessage: 'Tile Map Service', }); diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.test.ts b/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.test.ts new file mode 100644 index 0000000000000..5de85adde158f --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.test.ts @@ -0,0 +1,30 @@ +/* + * 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 { XYZTMSSource } from './xyz_tms_source'; +import { ILayer } from '../layer'; +import { TileLayer } from '../tile_layer'; +import { EMS_XYZ } from '../../../common/constants'; +import { IXYZTMSSourceDescriptor } from '../../../common/descriptor_types'; + +const descriptor: IXYZTMSSourceDescriptor = { + type: EMS_XYZ, + urlTemplate: 'https://example.com/{x}/{y}/{z}.png', + id: 'foobar', +}; +describe('xyz Tilemap Source', () => { + it('should create a tile-layer', () => { + const source = new XYZTMSSource(descriptor, null); + const layer: ILayer = source.createDefaultLayer(); + expect(layer instanceof TileLayer).toEqual(true); + }); + + it('should echo url template for url template', async () => { + const source = new XYZTMSSource(descriptor, null); + const template = await source.getUrlTemplate(); + expect(template).toEqual(descriptor.urlTemplate); + }); +}); diff --git a/x-pack/legacy/plugins/maps/public/layers/tile_layer.d.ts b/x-pack/legacy/plugins/maps/public/layers/tile_layer.d.ts new file mode 100644 index 0000000000000..fdb37a8af805f --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/tile_layer.d.ts @@ -0,0 +1,18 @@ +/* + * 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 { AbstractLayer, ILayerArguments } from './layer'; +import { ITMSSource } from './sources/tms_source'; +import { ILayerDescriptor } from '../../common/descriptor_types'; + +interface ITileLayerArguments extends ILayerArguments { + source: ITMSSource; + layerDescriptor: ILayerDescriptor; +} + +export class TileLayer extends AbstractLayer { + constructor(args: ITileLayerArguments); +} diff --git a/x-pack/legacy/plugins/maps/public/layers/tile_layer.test.ts b/x-pack/legacy/plugins/maps/public/layers/tile_layer.test.ts new file mode 100644 index 0000000000000..b2d2b08c637cf --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/tile_layer.test.ts @@ -0,0 +1,55 @@ +/* + * 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 { TileLayer } from './tile_layer'; +import { EMS_XYZ } from '../../common/constants'; +import { IXYZTMSSourceDescriptor } from '../../common/descriptor_types'; +import { ITMSSource } from './sources/tms_source'; +import { ILayer } from './layer'; + +const sourceDescriptor: IXYZTMSSourceDescriptor = { + type: EMS_XYZ, + urlTemplate: 'https://example.com/{x}/{y}/{z}.png', + id: 'foobar', +}; + +class MockTileSource implements ITMSSource { + private _descriptor: IXYZTMSSourceDescriptor; + constructor(descriptor: IXYZTMSSourceDescriptor) { + this._descriptor = descriptor; + } + createDefaultLayer(): ILayer { + throw new Error('not implemented'); + } + + async getDisplayName(): Promise { + return this._descriptor.urlTemplate; + } + + async getUrlTemplate(): Promise { + return 'template/{x}/{y}/{z}.png'; + } +} + +describe('TileLayer', () => { + it('should use display-label from source', async () => { + const source = new MockTileSource(sourceDescriptor); + const layer: ILayer = new TileLayer({ + source, + layerDescriptor: { id: 'layerid', sourceDescriptor }, + }); + expect(await source.getDisplayName()).toEqual(await layer.getDisplayName()); + }); + + it('should override with custom display-label if present', async () => { + const source = new MockTileSource(sourceDescriptor); + const layer: ILayer = new TileLayer({ + source, + layerDescriptor: { id: 'layerid', sourceDescriptor, label: 'custom' }, + }); + expect('custom').toEqual(await layer.getDisplayName()); + }); +}); From 4cb9bc44721e26ac2898eb11621b85f4418d913e Mon Sep 17 00:00:00 2001 From: Josh Dover Date: Wed, 26 Feb 2020 12:43:12 -0700 Subject: [PATCH 104/123] Add ScopedHistory to AppMountParams (#56705) --- .../core/public/kibana-plugin-public.app.md | 4 +- .../public/kibana-plugin-public.app.mount.md | 2 +- ...plugin-public.applicationsetup.register.md | 4 +- .../public/kibana-plugin-public.appmount.md | 2 +- ...kibana-plugin-public.appmountdeprecated.md | 2 +- ...n-public.appmountparameters.appbasepath.md | 9 +- ...lugin-public.appmountparameters.history.md | 58 +++ ...kibana-plugin-public.appmountparameters.md | 3 +- .../core/public/kibana-plugin-public.md | 1 + ...ugin-public.scopedhistory._constructor_.md | 21 ++ ...bana-plugin-public.scopedhistory.action.md | 13 + ...ibana-plugin-public.scopedhistory.block.md | 18 + ...-plugin-public.scopedhistory.createhref.md | 13 + ...n-public.scopedhistory.createsubhistory.md | 13 + .../kibana-plugin-public.scopedhistory.go.md | 13 + ...bana-plugin-public.scopedhistory.goback.md | 13 + ...a-plugin-public.scopedhistory.goforward.md | 13 + ...bana-plugin-public.scopedhistory.length.md | 13 + ...bana-plugin-public.scopedhistory.listen.md | 13 + ...na-plugin-public.scopedhistory.location.md | 13 + .../kibana-plugin-public.scopedhistory.md | 41 +++ ...kibana-plugin-public.scopedhistory.push.md | 13 + ...ana-plugin-public.scopedhistory.replace.md | 13 + .../application/application_service.test.ts | 30 ++ .../application/application_service.tsx | 17 +- src/core/public/application/index.ts | 1 + .../integration_tests/router.test.tsx | 136 ++++++-- .../application/integration_tests/utils.tsx | 22 +- .../public/application/scoped_history.mock.ts | 57 +++ .../public/application/scoped_history.test.ts | 329 ++++++++++++++++++ src/core/public/application/scoped_history.ts | 318 +++++++++++++++++ src/core/public/application/types.ts | 76 +++- .../application/ui/app_container.test.tsx | 7 + .../public/application/ui/app_container.tsx | 9 +- src/core/public/application/ui/app_router.tsx | 22 +- src/core/public/index.ts | 1 + src/core/public/mocks.ts | 1 + src/core/public/public.api.md | 36 +- .../local_application_service.ts | 8 +- .../new_platform/new_platform.test.mocks.ts | 7 + .../public/new_platform/new_platform.test.ts | 6 +- .../ui/public/new_platform/new_platform.ts | 19 +- src/plugins/dev_tools/public/application.tsx | 8 +- .../core_plugin_a/public/application.tsx | 14 +- .../core_plugin_b/public/application.tsx | 14 +- .../plugins/core_plugin_legacy/index.ts | 1 + .../plugins/legacy_plugin/index.ts | 34 ++ .../plugins/legacy_plugin/package.json | 17 + .../plugins/legacy_plugin/public/index.tsx | 35 ++ .../plugins/legacy_plugin/tsconfig.json | 15 + .../core_plugins/application_leave_confirm.ts | 2 +- .../test_suites/core_plugins/applications.ts | 28 +- .../core_plugins/legacy_plugins.ts | 2 +- .../test_suites/core_plugins/rendering.ts | 8 +- .../public/legacy.ts | 4 +- .../public/register_route.ts | 4 +- x-pack/legacy/plugins/ml/public/plugin.ts | 1 + .../plugins/uptime/public/apps/plugin.ts | 1 - 58 files changed, 1479 insertions(+), 119 deletions(-) create mode 100644 docs/development/core/public/kibana-plugin-public.appmountparameters.history.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory._constructor_.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.action.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.block.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.createhref.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.createsubhistory.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.go.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.goback.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.goforward.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.length.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.listen.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.location.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.push.md create mode 100644 docs/development/core/public/kibana-plugin-public.scopedhistory.replace.md create mode 100644 src/core/public/application/scoped_history.mock.ts create mode 100644 src/core/public/application/scoped_history.test.ts create mode 100644 src/core/public/application/scoped_history.ts create mode 100644 test/plugin_functional/plugins/legacy_plugin/index.ts create mode 100644 test/plugin_functional/plugins/legacy_plugin/package.json create mode 100644 test/plugin_functional/plugins/legacy_plugin/public/index.tsx create mode 100644 test/plugin_functional/plugins/legacy_plugin/tsconfig.json diff --git a/docs/development/core/public/kibana-plugin-public.app.md b/docs/development/core/public/kibana-plugin-public.app.md index faea94c467726..f31db3674f5ba 100644 --- a/docs/development/core/public/kibana-plugin-public.app.md +++ b/docs/development/core/public/kibana-plugin-public.app.md @@ -9,7 +9,7 @@ Extension of [common app properties](./kibana-plugin-public.appbase.md) with the Signature: ```typescript -export interface App extends AppBase +export interface App extends AppBase ``` ## Properties @@ -18,5 +18,5 @@ export interface App extends AppBase | --- | --- | --- | | [appRoute](./kibana-plugin-public.app.approute.md) | string | Override the application's routing path from /app/${id}. Must be unique across registered applications. Should not include the base path from HTTP. | | [chromeless](./kibana-plugin-public.app.chromeless.md) | boolean | Hide the UI chrome when the application is mounted. Defaults to false. Takes precedence over chrome service visibility settings. | -| [mount](./kibana-plugin-public.app.mount.md) | AppMount | AppMountDeprecated | A mount function called when the user navigates to this app's route. May have signature of [AppMount](./kibana-plugin-public.appmount.md) or [AppMountDeprecated](./kibana-plugin-public.appmountdeprecated.md). | +| [mount](./kibana-plugin-public.app.mount.md) | AppMount<HistoryLocationState> | AppMountDeprecated<HistoryLocationState> | A mount function called when the user navigates to this app's route. May have signature of [AppMount](./kibana-plugin-public.appmount.md) or [AppMountDeprecated](./kibana-plugin-public.appmountdeprecated.md). | diff --git a/docs/development/core/public/kibana-plugin-public.app.mount.md b/docs/development/core/public/kibana-plugin-public.app.mount.md index 2af5f0277759a..4829307ff267c 100644 --- a/docs/development/core/public/kibana-plugin-public.app.mount.md +++ b/docs/development/core/public/kibana-plugin-public.app.mount.md @@ -9,7 +9,7 @@ A mount function called when the user navigates to this app's route. May have si Signature: ```typescript -mount: AppMount | AppMountDeprecated; +mount: AppMount | AppMountDeprecated; ``` ## Remarks diff --git a/docs/development/core/public/kibana-plugin-public.applicationsetup.register.md b/docs/development/core/public/kibana-plugin-public.applicationsetup.register.md index 5c6c7cd252b0a..27c3e28c05a0d 100644 --- a/docs/development/core/public/kibana-plugin-public.applicationsetup.register.md +++ b/docs/development/core/public/kibana-plugin-public.applicationsetup.register.md @@ -9,14 +9,14 @@ Register an mountable application to the system. Signature: ```typescript -register(app: App): void; +register(app: App): void; ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| app | App | an [App](./kibana-plugin-public.app.md) | +| app | App<HistoryLocationState> | an [App](./kibana-plugin-public.app.md) | Returns: diff --git a/docs/development/core/public/kibana-plugin-public.appmount.md b/docs/development/core/public/kibana-plugin-public.appmount.md index 84a52b09a119c..a001b1f75c99e 100644 --- a/docs/development/core/public/kibana-plugin-public.appmount.md +++ b/docs/development/core/public/kibana-plugin-public.appmount.md @@ -9,5 +9,5 @@ A mount function called when the user navigates to this app's route. Signature: ```typescript -export declare type AppMount = (params: AppMountParameters) => AppUnmount | Promise; +export declare type AppMount = (params: AppMountParameters) => AppUnmount | Promise; ``` diff --git a/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md b/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md index 8c8114182b60f..2bd2e956124c0 100644 --- a/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md +++ b/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md @@ -13,7 +13,7 @@ A mount function called when the user navigates to this app's route. Signature: ```typescript -export declare type AppMountDeprecated = (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise; +export declare type AppMountDeprecated = (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise; ``` ## Remarks diff --git a/docs/development/core/public/kibana-plugin-public.appmountparameters.appbasepath.md b/docs/development/core/public/kibana-plugin-public.appmountparameters.appbasepath.md index 041d976aa42a2..beedda98d8f4d 100644 --- a/docs/development/core/public/kibana-plugin-public.appmountparameters.appbasepath.md +++ b/docs/development/core/public/kibana-plugin-public.appmountparameters.appbasepath.md @@ -4,6 +4,11 @@ ## AppMountParameters.appBasePath property +> Warning: This API is now obsolete. +> +> Use [AppMountParameters.history](./kibana-plugin-public.appmountparameters.history.md) instead. +> + The route path for configuring navigation to the application. This string should not include the base path from HTTP. Signature: @@ -39,10 +44,10 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter, Route } from 'react-router-dom'; -import { CoreStart, AppMountParams } from 'src/core/public'; +import { CoreStart, AppMountParameters } from 'src/core/public'; import { MyPluginDepsStart } from './plugin'; -export renderApp = ({ appBasePath, element }: AppMountParams) => { +export renderApp = ({ appBasePath, element }: AppMountParameters) => { ReactDOM.render( // pass `appBasePath` to `basename` diff --git a/docs/development/core/public/kibana-plugin-public.appmountparameters.history.md b/docs/development/core/public/kibana-plugin-public.appmountparameters.history.md new file mode 100644 index 0000000000000..9a3fa1a1bb48a --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.appmountparameters.history.md @@ -0,0 +1,58 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [AppMountParameters](./kibana-plugin-public.appmountparameters.md) > [history](./kibana-plugin-public.appmountparameters.history.md) + +## AppMountParameters.history property + +A scoped history instance for your application. Should be used to wire up your applications Router. + +Signature: + +```typescript +history: ScopedHistory; +``` + +## Example + +How to configure react-router with a base path: + +```ts +// inside your plugin's setup function +export class MyPlugin implements Plugin { + setup({ application }) { + application.register({ + id: 'my-app', + appRoute: '/my-app', + async mount(params) { + const { renderApp } = await import('./application'); + return renderApp(params); + }, + }); + } +} + +``` + +```ts +// application.tsx +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Router, Route } from 'react-router-dom'; + +import { CoreStart, AppMountParameters } from 'src/core/public'; +import { MyPluginDepsStart } from './plugin'; + +export renderApp = ({ element, history }: AppMountParameters) => { + ReactDOM.render( + // pass `appBasePath` to `basename` + + + , + element + ); + + return () => ReactDOM.unmountComponentAtNode(element); +} + +``` + diff --git a/docs/development/core/public/kibana-plugin-public.appmountparameters.md b/docs/development/core/public/kibana-plugin-public.appmountparameters.md index c21889c28bda4..e652379fc3034 100644 --- a/docs/development/core/public/kibana-plugin-public.appmountparameters.md +++ b/docs/development/core/public/kibana-plugin-public.appmountparameters.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface AppMountParameters +export interface AppMountParameters ``` ## Properties @@ -17,5 +17,6 @@ export interface AppMountParameters | --- | --- | --- | | [appBasePath](./kibana-plugin-public.appmountparameters.appbasepath.md) | string | The route path for configuring navigation to the application. This string should not include the base path from HTTP. | | [element](./kibana-plugin-public.appmountparameters.element.md) | HTMLElement | The container element to render the application into. | +| [history](./kibana-plugin-public.appmountparameters.history.md) | ScopedHistory<HistoryLocationState> | A scoped history instance for your application. Should be used to wire up your applications Router. | | [onAppLeave](./kibana-plugin-public.appmountparameters.onappleave.md) | (handler: AppLeaveHandler) => void | A function that can be used to register a handler that will be called when the user is leaving the current application, allowing to prompt a confirmation message before actually changing the page.This will be called either when the user goes to another application, or when trying to close the tab or manually changing the url. | diff --git a/docs/development/core/public/kibana-plugin-public.md b/docs/development/core/public/kibana-plugin-public.md index 95a4327728139..79bdb11b80fa4 100644 --- a/docs/development/core/public/kibana-plugin-public.md +++ b/docs/development/core/public/kibana-plugin-public.md @@ -15,6 +15,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | Class | Description | | --- | --- | | [SavedObjectsClient](./kibana-plugin-public.savedobjectsclient.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing plugin state. The client-side SavedObjectsClient is a thin convenience library around the SavedObjects HTTP API for interacting with Saved Objects. | +| [ScopedHistory](./kibana-plugin-public.scopedhistory.md) | A wrapper around a History instance that is scoped to a particular base path of the history stack. Behaves similarly to the basename option except that this wrapper hides any history stack entries from outside the scope of this base path.This wrapper also allows Core and Plugins to share a single underlying global History instance without exposing the history of other applications.The [createSubHistory](./kibana-plugin-public.scopedhistory.createsubhistory.md) method is particularly useful for applications that contain any number of "sub-apps" which should not have access to the main application's history or basePath. | | [SimpleSavedObject](./kibana-plugin-public.simplesavedobject.md) | This class is a very simple wrapper for SavedObjects loaded from the server with the [SavedObjectsClient](./kibana-plugin-public.savedobjectsclient.md).It provides basic functionality for creating/saving/deleting saved objects, but doesn't include any type-specific implementations. | | [ToastsApi](./kibana-plugin-public.toastsapi.md) | Methods for adding and removing global toast messages. | diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory._constructor_.md b/docs/development/core/public/kibana-plugin-public.scopedhistory._constructor_.md new file mode 100644 index 0000000000000..d21c908890b6b --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory._constructor_.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [(constructor)](./kibana-plugin-public.scopedhistory._constructor_.md) + +## ScopedHistory.(constructor) + +Constructs a new instance of the `ScopedHistory` class + +Signature: + +```typescript +constructor(parentHistory: History, basePath: string); +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| parentHistory | History | | +| basePath | string | | + diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.action.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.action.md new file mode 100644 index 0000000000000..c3b52b9041871 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.action.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [action](./kibana-plugin-public.scopedhistory.action.md) + +## ScopedHistory.action property + +The last action dispatched on the history stack. + +Signature: + +```typescript +get action(): Action; +``` diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.block.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.block.md new file mode 100644 index 0000000000000..b6c5da58d4684 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.block.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [block](./kibana-plugin-public.scopedhistory.block.md) + +## ScopedHistory.block property + +Not supported. Use [AppMountParameters.onAppLeave](./kibana-plugin-public.appmountparameters.onappleave.md). + +Signature: + +```typescript +block: (prompt?: string | boolean | History.TransitionPromptHook | undefined) => UnregisterCallback; +``` + +## Remarks + +We prefer that applications use the `onAppLeave` API because it supports a more graceful experience that prefers a modal when possible, falling back to a confirm dialog box in the beforeunload case. + diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.createhref.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.createhref.md new file mode 100644 index 0000000000000..6bbd78dc9b3c9 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.createhref.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [createHref](./kibana-plugin-public.scopedhistory.createhref.md) + +## ScopedHistory.createHref property + +Creates an href (string) to the location. + +Signature: + +```typescript +createHref: (location: LocationDescriptorObject) => string; +``` diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.createsubhistory.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.createsubhistory.md new file mode 100644 index 0000000000000..045289c98e4ee --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.createsubhistory.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [createSubHistory](./kibana-plugin-public.scopedhistory.createsubhistory.md) + +## ScopedHistory.createSubHistory property + +Creates a `ScopedHistory` for a subpath of this `ScopedHistory`. Useful for applications that may have sub-apps that do not need access to the containing application's history. + +Signature: + +```typescript +createSubHistory: (basePath: string) => ScopedHistory; +``` diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.go.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.go.md new file mode 100644 index 0000000000000..b9d124d06a109 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.go.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [go](./kibana-plugin-public.scopedhistory.go.md) + +## ScopedHistory.go property + +Send the user forward or backwards in the history stack. + +Signature: + +```typescript +go: (n: number) => void; +``` diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.goback.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.goback.md new file mode 100644 index 0000000000000..8f1d4b25ebcbf --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.goback.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [goBack](./kibana-plugin-public.scopedhistory.goback.md) + +## ScopedHistory.goBack property + +Send the user one location back in the history stack. Equivalent to calling [ScopedHistory.go(-1)](./kibana-plugin-public.scopedhistory.go.md). If no more entries are available backwards, this is a no-op. + +Signature: + +```typescript +goBack: () => void; +``` diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.goforward.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.goforward.md new file mode 100644 index 0000000000000..587d5035bb5b5 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.goforward.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [goForward](./kibana-plugin-public.scopedhistory.goforward.md) + +## ScopedHistory.goForward property + +Send the user one location forward in the history stack. Equivalent to calling [ScopedHistory.go(1)](./kibana-plugin-public.scopedhistory.go.md). If no more entries are available forwards, this is a no-op. + +Signature: + +```typescript +goForward: () => void; +``` diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.length.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.length.md new file mode 100644 index 0000000000000..8a8d6accc1fbc --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.length.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [length](./kibana-plugin-public.scopedhistory.length.md) + +## ScopedHistory.length property + +The number of entries in the history stack, including all entries forwards and backwards from the current location. + +Signature: + +```typescript +get length(): number; +``` diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.listen.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.listen.md new file mode 100644 index 0000000000000..a0693e5a0428d --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.listen.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [listen](./kibana-plugin-public.scopedhistory.listen.md) + +## ScopedHistory.listen property + +Adds a listener for location updates. + +Signature: + +```typescript +listen: (listener: (location: Location, action: Action) => void) => UnregisterCallback; +``` diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.location.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.location.md new file mode 100644 index 0000000000000..c40f73333ec7d --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.location.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [location](./kibana-plugin-public.scopedhistory.location.md) + +## ScopedHistory.location property + +The current location of the history stack. + +Signature: + +```typescript +get location(): Location; +``` diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.md new file mode 100644 index 0000000000000..5b429c1e6ec9e --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.md @@ -0,0 +1,41 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) + +## ScopedHistory class + +A wrapper around a `History` instance that is scoped to a particular base path of the history stack. Behaves similarly to the `basename` option except that this wrapper hides any history stack entries from outside the scope of this base path. + +This wrapper also allows Core and Plugins to share a single underlying global `History` instance without exposing the history of other applications. + +The [createSubHistory](./kibana-plugin-public.scopedhistory.createsubhistory.md) method is particularly useful for applications that contain any number of "sub-apps" which should not have access to the main application's history or basePath. + +Signature: + +```typescript +export declare class ScopedHistory implements History +``` + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)(parentHistory, basePath)](./kibana-plugin-public.scopedhistory._constructor_.md) | | Constructs a new instance of the ScopedHistory class | + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [action](./kibana-plugin-public.scopedhistory.action.md) | | Action | The last action dispatched on the history stack. | +| [block](./kibana-plugin-public.scopedhistory.block.md) | | (prompt?: string | boolean | History.TransitionPromptHook<HistoryLocationState> | undefined) => UnregisterCallback | Not supported. Use [AppMountParameters.onAppLeave](./kibana-plugin-public.appmountparameters.onappleave.md). | +| [createHref](./kibana-plugin-public.scopedhistory.createhref.md) | | (location: LocationDescriptorObject<HistoryLocationState>) => string | Creates an href (string) to the location. | +| [createSubHistory](./kibana-plugin-public.scopedhistory.createsubhistory.md) | | <SubHistoryLocationState = unknown>(basePath: string) => ScopedHistory<SubHistoryLocationState> | Creates a ScopedHistory for a subpath of this ScopedHistory. Useful for applications that may have sub-apps that do not need access to the containing application's history. | +| [go](./kibana-plugin-public.scopedhistory.go.md) | | (n: number) => void | Send the user forward or backwards in the history stack. | +| [goBack](./kibana-plugin-public.scopedhistory.goback.md) | | () => void | Send the user one location back in the history stack. Equivalent to calling [ScopedHistory.go(-1)](./kibana-plugin-public.scopedhistory.go.md). If no more entries are available backwards, this is a no-op. | +| [goForward](./kibana-plugin-public.scopedhistory.goforward.md) | | () => void | Send the user one location forward in the history stack. Equivalent to calling [ScopedHistory.go(1)](./kibana-plugin-public.scopedhistory.go.md). If no more entries are available forwards, this is a no-op. | +| [length](./kibana-plugin-public.scopedhistory.length.md) | | number | The number of entries in the history stack, including all entries forwards and backwards from the current location. | +| [listen](./kibana-plugin-public.scopedhistory.listen.md) | | (listener: (location: Location<HistoryLocationState>, action: Action) => void) => UnregisterCallback | Adds a listener for location updates. | +| [location](./kibana-plugin-public.scopedhistory.location.md) | | Location<HistoryLocationState> | The current location of the history stack. | +| [push](./kibana-plugin-public.scopedhistory.push.md) | | (pathOrLocation: string | LocationDescriptorObject<HistoryLocationState>, state?: HistoryLocationState | undefined) => void | Pushes a new location onto the history stack. If there are forward entries in the stack, they will be removed. | +| [replace](./kibana-plugin-public.scopedhistory.replace.md) | | (pathOrLocation: string | LocationDescriptorObject<HistoryLocationState>, state?: HistoryLocationState | undefined) => void | Replaces the current location in the history stack. Does not remove forward or backward entries. | + diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.push.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.push.md new file mode 100644 index 0000000000000..0d8d635d0f189 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.push.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [push](./kibana-plugin-public.scopedhistory.push.md) + +## ScopedHistory.push property + +Pushes a new location onto the history stack. If there are forward entries in the stack, they will be removed. + +Signature: + +```typescript +push: (pathOrLocation: string | LocationDescriptorObject, state?: HistoryLocationState | undefined) => void; +``` diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.replace.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.replace.md new file mode 100644 index 0000000000000..f9c1171d4217e --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.replace.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [replace](./kibana-plugin-public.scopedhistory.replace.md) + +## ScopedHistory.replace property + +Replaces the current location in the history stack. Does not remove forward or backward entries. + +Signature: + +```typescript +replace: (pathOrLocation: string | LocationDescriptorObject, state?: HistoryLocationState | undefined) => void; +``` diff --git a/src/core/public/application/application_service.test.ts b/src/core/public/application/application_service.test.ts index 5487ca53170dd..c25918c6b7328 100644 --- a/src/core/public/application/application_service.test.ts +++ b/src/core/public/application/application_service.test.ts @@ -588,6 +588,16 @@ describe('#start()', () => { expect(getUrlForApp('app1', { path: 'deep/link///' })).toBe('/base-path/app/app1/deep/link'); }); + it('does not append trailing slash if hash is provided in path parameter', async () => { + service.setup(setupDeps); + const { getUrlForApp } = await service.start(startDeps); + + expect(getUrlForApp('app1', { path: '#basic-hash' })).toBe('/base-path/app/app1#basic-hash'); + expect(getUrlForApp('app1', { path: '#/hash/router/path' })).toBe( + '/base-path/app/app1#/hash/router/path' + ); + }); + it('creates absolute URLs when `absolute` parameter is true', async () => { service.setup(setupDeps); const { getUrlForApp } = await service.start(startDeps); @@ -646,6 +656,26 @@ describe('#start()', () => { ); }); + it('appends a path if specified with hash', async () => { + const { register } = service.setup(setupDeps); + + register(Symbol(), createApp({ id: 'app2', appRoute: '/custom/path' })); + + const { navigateToApp } = await service.start(startDeps); + + await navigateToApp('myTestApp', { path: '#basic-hash' }); + expect(MockHistory.push).toHaveBeenCalledWith('/app/myTestApp#basic-hash', undefined); + + await navigateToApp('myTestApp', { path: '#/hash/router/path' }); + expect(MockHistory.push).toHaveBeenCalledWith('/app/myTestApp#/hash/router/path', undefined); + + await navigateToApp('app2', { path: '#basic-hash' }); + expect(MockHistory.push).toHaveBeenCalledWith('/custom/path#basic-hash', undefined); + + await navigateToApp('app2', { path: '#/hash/router/path' }); + expect(MockHistory.push).toHaveBeenCalledWith('/custom/path#/hash/router/path', undefined); + }); + it('includes state if specified', async () => { const { register } = service.setup(setupDeps); diff --git a/src/core/public/application/application_service.tsx b/src/core/public/application/application_service.tsx index 77f06e316c0aa..1c9492d81c7f6 100644 --- a/src/core/public/application/application_service.tsx +++ b/src/core/public/application/application_service.tsx @@ -76,10 +76,19 @@ function filterAvailable(m: Map, capabilities: Capabilities) { } const findMounter = (mounters: Map, appRoute?: string) => [...mounters].find(([, mounter]) => mounter.appRoute === appRoute); -const getAppUrl = (mounters: Map, appId: string, path: string = '') => - `/${mounters.get(appId)?.appRoute ?? `/app/${appId}`}/${path}` + +const getAppUrl = (mounters: Map, appId: string, path: string = '') => { + const appBasePath = mounters.get(appId)?.appRoute + ? `/${mounters.get(appId)!.appRoute}` + : `/app/${appId}`; + + // Only preppend slash if not a hash or query path + path = path.startsWith('#') || path.startsWith('?') ? path : `/${path}`; + + return `${appBasePath}${path}` .replace(/\/{2,}/g, '/') // Remove duplicate slashes .replace(/\/$/, ''); // Remove trailing slash +}; const allApplicationsFilter = '__ALL__'; @@ -93,7 +102,7 @@ interface AppUpdaterWrapper { * @internal */ export class ApplicationService { - private readonly apps = new Map(); + private readonly apps = new Map | LegacyApp>(); private readonly mounters = new Map(); private readonly capabilities = new CapabilitiesService(); private readonly appLeaveHandlers = new Map(); @@ -143,7 +152,7 @@ export class ApplicationService { return { registerMountContext: this.mountContext!.registerContext, - register: (plugin, app) => { + register: (plugin, app: App) => { app = { appRoute: `/app/${app.id}`, ...app }; if (this.registrationClosed) { diff --git a/src/core/public/application/index.ts b/src/core/public/application/index.ts index e7ea330657648..ec10d2bc22871 100644 --- a/src/core/public/application/index.ts +++ b/src/core/public/application/index.ts @@ -19,6 +19,7 @@ export { ApplicationService } from './application_service'; export { Capabilities } from './capabilities'; +export { ScopedHistory } from './scoped_history'; export { App, AppBase, diff --git a/src/core/public/application/integration_tests/router.test.tsx b/src/core/public/application/integration_tests/router.test.tsx index 0c5f5a138d58f..2f26bc1409104 100644 --- a/src/core/public/application/integration_tests/router.test.tsx +++ b/src/core/public/application/integration_tests/router.test.tsx @@ -25,15 +25,17 @@ import { AppRouter, AppNotFound } from '../ui'; import { EitherApp, MockedMounterMap, MockedMounterTuple } from '../test_types'; import { createRenderer, createAppMounter, createLegacyAppMounter, getUnmounter } from './utils'; import { AppStatus } from '../types'; +import { ScopedHistory } from '../scoped_history'; describe('AppContainer', () => { let mounters: MockedMounterMap; - let history: History; + let globalHistory: History; let appStatuses$: BehaviorSubject>; let update: ReturnType; + let scopedAppHistory: History; const navigate = (path: string) => { - history.push(path); + globalHistory.push(path); return update(); }; const mockMountersToMounters = () => @@ -53,20 +55,35 @@ describe('AppContainer', () => { beforeEach(() => { mounters = new Map([ - createAppMounter('app1', 'App 1'), + createAppMounter({ appId: 'app1', html: 'App 1' }), createLegacyAppMounter('legacyApp1', jest.fn()), - createAppMounter('app2', '
App 2
'), + createAppMounter({ appId: 'app2', html: '
App 2
' }), createLegacyAppMounter('baseApp:legacyApp2', jest.fn()), - createAppMounter('app3', '
Chromeless A
', '/chromeless-a/path'), - createAppMounter('app4', '
Chromeless B
', '/chromeless-b/path'), - createAppMounter('disabledApp', '
Disabled app
'), + createAppMounter({ + appId: 'app3', + html: '
Chromeless A
', + appRoute: '/chromeless-a/path', + }), + createAppMounter({ + appId: 'app4', + html: '
Chromeless B
', + appRoute: '/chromeless-b/path', + }), + createAppMounter({ appId: 'disabledApp', html: '
Disabled app
' }), createLegacyAppMounter('disabledLegacyApp', jest.fn()), + createAppMounter({ + appId: 'scopedApp', + extraMountHook: ({ history }) => { + scopedAppHistory = history; + history.push('/subpath'); + }, + }), ] as Array>); - history = createMemoryHistory(); + globalHistory = createMemoryHistory(); appStatuses$ = mountersToAppStatus$(); update = createRenderer( { }); it('should not mount when partial route path matches', async () => { - mounters.set(...createAppMounter('spaces', '
Custom Space
', '/spaces/fake-login')); - mounters.set(...createAppMounter('login', '
Login Page
', '/fake-login')); - history = createMemoryHistory(); + mounters.set( + ...createAppMounter({ + appId: 'spaces', + html: '
Custom Space
', + appRoute: '/spaces/fake-login', + }) + ); + mounters.set( + ...createAppMounter({ + appId: 'login', + html: '
Login Page
', + appRoute: '/fake-login', + }) + ); + globalHistory = createMemoryHistory(); update = createRenderer( { }); it('should not mount when partial route path has higher specificity', async () => { - mounters.set(...createAppMounter('login', '
Login Page
', '/fake-login')); - mounters.set(...createAppMounter('spaces', '
Custom Space
', '/spaces/fake-login')); - history = createMemoryHistory(); + mounters.set( + ...createAppMounter({ + appId: 'login', + html: '
Login Page
', + appRoute: '/fake-login', + }) + ); + mounters.set( + ...createAppMounter({ + appId: 'spaces', + html: '
Custom Space
', + appRoute: '/spaces/fake-login', + }) + ); + globalHistory = createMemoryHistory(); update = createRenderer( { // Hitting back button within app does not trigger re-render await navigate('/app/app1/page2'); - history.goBack(); + globalHistory.goBack(); await update(); expect(mounter.mount).toHaveBeenCalledTimes(1); expect(unmount).not.toHaveBeenCalled(); }); it('should not remount when when changing pages within app using hash history', async () => { - history = createHashHistory(); + globalHistory = createHashHistory(); update = createRenderer( { expect(unmount).toHaveBeenCalledTimes(1); }); + it('pushes global history changes to inner scoped history', async () => { + const scopedApp = mounters.get('scopedApp'); + await navigate('/app/scopedApp'); + + // Verify that internal app's redirect propagated + expect(scopedApp?.mounter.mount).toHaveBeenCalledTimes(1); + expect(scopedAppHistory.location.pathname).toEqual('/subpath'); + expect(globalHistory.location.pathname).toEqual('/app/scopedApp/subpath'); + + // Simulate user clicking on navlink again to return to app root + globalHistory.push('/app/scopedApp'); + // Should not call mount again + expect(scopedApp?.mounter.mount).toHaveBeenCalledTimes(1); + expect(scopedApp?.unmount).not.toHaveBeenCalled(); + // Inner scoped history should be synced + expect(scopedAppHistory.location.pathname).toEqual(''); + + // Make sure going back to subpath works + globalHistory.goBack(); + expect(scopedApp?.mounter.mount).toHaveBeenCalledTimes(1); + expect(scopedApp?.unmount).not.toHaveBeenCalled(); + expect(scopedAppHistory.location.pathname).toEqual('/subpath'); + expect(globalHistory.location.pathname).toEqual('/app/scopedApp/subpath'); + }); + it('calls legacy mount handler', async () => { await navigate('/app/legacyApp1'); - expect(mounters.get('legacyApp1')!.mounter.mount.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "appBasePath": "/app/legacyApp1", - "element":
, - "onAppLeave": [Function], - }, - ] - `); + expect(mounters.get('legacyApp1')!.mounter.mount.mock.calls[0][0]).toMatchObject({ + appBasePath: '/app/legacyApp1', + element: expect.any(HTMLDivElement), + onAppLeave: expect.any(Function), + history: expect.any(ScopedHistory), + }); }); it('handles legacy apps with subapps', async () => { await navigate('/app/baseApp'); - expect(mounters.get('baseApp:legacyApp2')!.mounter.mount.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "appBasePath": "/app/baseApp", - "element":
, - "onAppLeave": [Function], - }, - ] - `); + expect(mounters.get('baseApp:legacyApp2')!.mounter.mount.mock.calls[0][0]).toMatchObject({ + appBasePath: '/app/baseApp', + element: expect.any(HTMLDivElement), + onAppLeave: expect.any(Function), + history: expect.any(ScopedHistory), + }); }); it('displays error page if no app is found', async () => { diff --git a/src/core/public/application/integration_tests/utils.tsx b/src/core/public/application/integration_tests/utils.tsx index 4f34438fc822a..9092177da5ad4 100644 --- a/src/core/public/application/integration_tests/utils.tsx +++ b/src/core/public/application/integration_tests/utils.tsx @@ -40,11 +40,17 @@ export const createRenderer = (element: ReactElement | null): Renderer => { }); }; -export const createAppMounter = ( - appId: string, - html: string, - appRoute = `/app/${appId}` -): MockedMounterTuple => { +export const createAppMounter = ({ + appId, + html = `
App ${appId}
`, + appRoute = `/app/${appId}`, + extraMountHook, +}: { + appId: string; + html?: string; + appRoute?: string; + extraMountHook?: (params: AppMountParameters) => void; +}): MockedMounterTuple => { const unmount = jest.fn(); return [ appId, @@ -52,11 +58,15 @@ export const createAppMounter = ( mounter: { appRoute, appBasePath: appRoute, - mount: jest.fn(async ({ appBasePath: basename, element }: AppMountParameters) => { + mount: jest.fn(async (params: AppMountParameters) => { + const { appBasePath: basename, element } = params; Object.assign(element, { innerHTML: `
\nbasename: ${basename}\nhtml: ${html}\n
`, }); unmount.mockImplementation(() => Object.assign(element, { innerHTML: '' })); + if (extraMountHook) { + extraMountHook(params); + } return unmount; }), }, diff --git a/src/core/public/application/scoped_history.mock.ts b/src/core/public/application/scoped_history.mock.ts new file mode 100644 index 0000000000000..56de97e630bf0 --- /dev/null +++ b/src/core/public/application/scoped_history.mock.ts @@ -0,0 +1,57 @@ +/* + * 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 { Location } from 'history'; +import { ScopedHistory } from './scoped_history'; + +type ScopedHistoryMock = jest.Mocked>; +const createMock = ({ + pathname = '/', + search = '', + hash = '', + key, + state, +}: Partial = {}) => { + const mock: ScopedHistoryMock = { + block: jest.fn(), + createHref: jest.fn(), + createSubHistory: jest.fn(), + go: jest.fn(), + goBack: jest.fn(), + goForward: jest.fn(), + listen: jest.fn(), + push: jest.fn(), + replace: jest.fn(), + action: 'PUSH', + length: 1, + location: { + pathname, + search, + state, + hash, + key, + }, + }; + + return mock; +}; + +export const scopedHistoryMock = { + create: createMock, +}; diff --git a/src/core/public/application/scoped_history.test.ts b/src/core/public/application/scoped_history.test.ts new file mode 100644 index 0000000000000..c01eb50830516 --- /dev/null +++ b/src/core/public/application/scoped_history.test.ts @@ -0,0 +1,329 @@ +/* + * 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 { ScopedHistory } from './scoped_history'; +import { createMemoryHistory } from 'history'; + +describe('ScopedHistory', () => { + describe('construction', () => { + it('succeeds if current location matches basePath', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + expect(() => new ScopedHistory(gh, '/app/wow')).not.toThrow(); + gh.push('/app/wow/'); + expect(() => new ScopedHistory(gh, '/app/wow')).not.toThrow(); + gh.push('/app/wow/sub-page'); + expect(() => new ScopedHistory(gh, '/app/wow')).not.toThrow(); + }); + + it('fails if current location does not match basePath', () => { + const gh = createMemoryHistory(); + gh.push('/app/other'); + expect(() => new ScopedHistory(gh, '/app/wow')).toThrowErrorMatchingInlineSnapshot( + `"Browser location [/app/other] is not currently in expected basePath [/app/wow]"` + ); + }); + }); + + describe('navigation', () => { + it('supports push', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + const pushSpy = jest.spyOn(gh, 'push'); + const h = new ScopedHistory(gh, '/app/wow'); + h.push('/new-page', { some: 'state' }); + expect(pushSpy).toHaveBeenCalledWith('/app/wow/new-page', { some: 'state' }); + expect(gh.length).toBe(3); // ['', '/app/wow', '/app/wow/new-page'] + expect(h.length).toBe(2); + }); + + it('supports unbound push', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + const pushSpy = jest.spyOn(gh, 'push'); + const h = new ScopedHistory(gh, '/app/wow'); + const { push } = h; + push('/new-page', { some: 'state' }); + expect(pushSpy).toHaveBeenCalledWith('/app/wow/new-page', { some: 'state' }); + expect(gh.length).toBe(3); // ['', '/app/wow', '/app/wow/new-page'] + expect(h.length).toBe(2); + }); + + it('supports replace', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + const replaceSpy = jest.spyOn(gh, 'replace'); + const h = new ScopedHistory(gh, '/app/wow'); // [''] + h.push('/first-page'); // ['', '/first-page'] + h.push('/second-page'); // ['', '/first-page', '/second-page'] + h.goBack(); // ['', '/first-page', '/second-page'] + h.replace('/first-page-replacement', { some: 'state' }); // ['', '/first-page-replacement', '/second-page'] + expect(replaceSpy).toHaveBeenCalledWith('/app/wow/first-page-replacement', { some: 'state' }); + expect(h.length).toBe(3); + expect(gh.length).toBe(4); // ['', '/app/wow', '/app/wow/first-page-replacement', '/app/wow/second-page'] + }); + + it('hides previous stack', () => { + const gh = createMemoryHistory(); + gh.push('/app/alpha'); + gh.push('/app/beta'); + gh.push('/app/wow'); + const h = new ScopedHistory(gh, '/app/wow'); + expect(h.length).toBe(1); + expect(h.location.pathname).toEqual(''); + }); + + it('cannot go back further than local stack', () => { + const gh = createMemoryHistory(); + gh.push('/app/alpha'); + gh.push('/app/beta'); + gh.push('/app/wow'); + const h = new ScopedHistory(gh, '/app/wow'); + h.push('/new-page'); + expect(h.length).toBe(2); + expect(h.location.pathname).toEqual('/new-page'); + + // Test first back + h.goBack(); + expect(h.length).toBe(2); + expect(h.location.pathname).toEqual(''); + expect(gh.location.pathname).toEqual('/app/wow'); + + // Second back should be no-op + h.goBack(); + expect(h.length).toBe(2); + expect(h.location.pathname).toEqual(''); + expect(gh.location.pathname).toEqual('/app/wow'); + }); + + it('cannot go forward further than local stack', () => { + const gh = createMemoryHistory(); + gh.push('/app/alpha'); + gh.push('/app/beta'); + gh.push('/app/wow'); + const h = new ScopedHistory(gh, '/app/wow'); + h.push('/new-page'); + expect(h.length).toBe(2); + + // Go back so we can go forward + h.goBack(); + expect(h.length).toBe(2); + expect(h.location.pathname).toEqual(''); + expect(gh.location.pathname).toEqual('/app/wow'); + + // Going forward should increase length and return to /new-page + h.goForward(); + expect(h.length).toBe(2); + expect(h.location.pathname).toEqual('/new-page'); + expect(gh.location.pathname).toEqual('/app/wow/new-page'); + + // Second forward should be no-op + h.goForward(); + expect(h.length).toBe(2); + expect(h.location.pathname).toEqual('/new-page'); + expect(gh.location.pathname).toEqual('/app/wow/new-page'); + }); + + it('reacts to navigations from parent history', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + const h = new ScopedHistory(gh, '/app/wow'); + h.push('/page-1'); + h.push('/page-2'); + + gh.goBack(); + expect(h.location.pathname).toEqual('/page-1'); + expect(h.length).toBe(3); + + gh.goForward(); + expect(h.location.pathname).toEqual('/page-2'); + expect(h.length).toBe(3); + + // Go back to /app/wow and push a new location + gh.goBack(); + gh.goBack(); + gh.push('/app/wow/page-3'); + expect(h.location.pathname).toEqual('/page-3'); + expect(h.length).toBe(2); // ['', '/page-3'] + }); + + it('increments length on push and removes length when going back and then pushing', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + expect(gh.length).toBe(2); + const h = new ScopedHistory(gh, '/app/wow'); + expect(h.length).toBe(1); + h.push('/page1'); + expect(h.length).toBe(2); + h.push('/page2'); + expect(h.length).toBe(3); + h.push('/page3'); + expect(h.length).toBe(4); + h.push('/page4'); + expect(h.length).toBe(5); + h.push('/page5'); + expect(h.length).toBe(6); + h.goBack(); // back/forward should not reduce the length + expect(h.length).toBe(6); + h.goBack(); + expect(h.length).toBe(6); + h.push('/page6'); // length should only change if a new location is pushed from a point further back in the history + expect(h.length).toBe(5); + h.goBack(); + expect(h.length).toBe(5); + h.goBack(); + expect(h.length).toBe(5); + h.push('/page7'); + expect(h.length).toBe(4); + }); + }); + + describe('teardown behavior', () => { + it('throws exceptions after falling out of scope', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + expect(gh.length).toBe(2); + const h = new ScopedHistory(gh, '/app/wow'); + gh.push('/app/other'); + expect(() => h.location).toThrowErrorMatchingInlineSnapshot( + `"ScopedHistory instance has fell out of navigation scope for basePath: /app/wow"` + ); + expect(() => h.push('/new-page')).toThrow(); + expect(() => h.replace('/new-page')).toThrow(); + expect(() => h.goBack()).toThrow(); + expect(() => h.goForward()).toThrow(); + }); + }); + + describe('listen', () => { + it('calls callback with scoped location', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + const h = new ScopedHistory(gh, '/app/wow'); + const listenPaths: string[] = []; + h.listen(l => listenPaths.push(l.pathname)); + h.push('/first-page'); + h.push('/second-page'); + h.push('/third-page'); + h.go(-2); + h.goForward(); + expect(listenPaths).toEqual([ + '/first-page', + '/second-page', + '/third-page', + '/first-page', + '/second-page', + ]); + }); + + it('stops calling callback after unlisten is called', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + const h = new ScopedHistory(gh, '/app/wow'); + const listenPaths: string[] = []; + const unlisten = h.listen(l => listenPaths.push(l.pathname)); + h.push('/first-page'); + unlisten(); + h.push('/second-page'); + h.push('/third-page'); + h.go(-2); + h.goForward(); + expect(listenPaths).toEqual(['/first-page']); + }); + + it('stops calling callback after browser leaves scope', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + const h = new ScopedHistory(gh, '/app/wow'); + const listenPaths: string[] = []; + h.listen(l => listenPaths.push(l.pathname)); + h.push('/first-page'); + gh.push('/app/other'); + gh.push('/second-page'); + gh.push('/third-page'); + gh.go(-2); + gh.goForward(); + expect(listenPaths).toEqual(['/first-page']); + }); + }); + + describe('createHref', () => { + it('creates scoped hrefs', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + const h = new ScopedHistory(gh, '/app/wow'); + expect(h.createHref({ pathname: '' })).toEqual(`/`); + expect(h.createHref({ pathname: '/new-page', search: '?alpha=true' })).toEqual( + `/new-page?alpha=true` + ); + }); + }); + + describe('action', () => { + it('provides last history action', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + gh.push('/alpha'); + gh.goBack(); + const h = new ScopedHistory(gh, '/app/wow'); + expect(h.action).toBe('POP'); + gh.push('/app/wow/page-1'); + expect(h.action).toBe('PUSH'); + h.replace('/page-2'); + expect(h.action).toBe('REPLACE'); + }); + }); + + describe('createSubHistory', () => { + it('supports push', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + const ghPushSpy = jest.spyOn(gh, 'push'); + const h1 = new ScopedHistory(gh, '/app/wow'); + h1.push('/new-page'); + const h1PushSpy = jest.spyOn(h1, 'push'); + const h2 = h1.createSubHistory('/new-page'); + h2.push('/sub-page', { some: 'state' }); + expect(h1PushSpy).toHaveBeenCalledWith('/new-page/sub-page', { some: 'state' }); + expect(ghPushSpy).toHaveBeenCalledWith('/app/wow/new-page/sub-page', { some: 'state' }); + expect(h2.length).toBe(2); + expect(h1.length).toBe(3); + expect(gh.length).toBe(4); + }); + + it('supports replace', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + const ghReplaceSpy = jest.spyOn(gh, 'replace'); + const h1 = new ScopedHistory(gh, '/app/wow'); + h1.push('/new-page'); + const h1ReplaceSpy = jest.spyOn(h1, 'replace'); + const h2 = h1.createSubHistory('/new-page'); + h2.push('/sub-page'); + h2.replace('/other-sub-page', { some: 'state' }); + expect(h1ReplaceSpy).toHaveBeenCalledWith('/new-page/other-sub-page', { some: 'state' }); + expect(ghReplaceSpy).toHaveBeenCalledWith('/app/wow/new-page/other-sub-page', { + some: 'state', + }); + expect(h2.length).toBe(2); + expect(h1.length).toBe(3); + expect(gh.length).toBe(4); + }); + }); +}); diff --git a/src/core/public/application/scoped_history.ts b/src/core/public/application/scoped_history.ts new file mode 100644 index 0000000000000..c5febc7604feb --- /dev/null +++ b/src/core/public/application/scoped_history.ts @@ -0,0 +1,318 @@ +/* + * 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 { + History, + Path, + LocationDescriptorObject, + TransitionPromptHook, + UnregisterCallback, + LocationListener, + Location, + Href, + Action, +} from 'history'; + +/** + * A wrapper around a `History` instance that is scoped to a particular base path of the history stack. Behaves + * similarly to the `basename` option except that this wrapper hides any history stack entries from outside the scope + * of this base path. + * + * This wrapper also allows Core and Plugins to share a single underlying global `History` instance without exposing + * the history of other applications. + * + * The {@link ScopedHistory.createSubHistory | createSubHistory} method is particularly useful for applications that + * contain any number of "sub-apps" which should not have access to the main application's history or basePath. + * + * @public + */ +export class ScopedHistory + implements History { + /** + * Tracks whether or not the user has left this history's scope. All methods throw errors if called after scope has + * been left. + */ + private isActive = true; + /** + * All active listeners on this history instance. + */ + private listeners = new Set>(); + /** + * Array of the local history stack. Only stores {@link Location.key} to use tracking an index of the current + * position of the window in the history stack. + */ + private locationKeys: Array = []; + /** + * The key of the current position of the window in the history stack. + */ + private currentLocationKeyIndex: number = 0; + + constructor(private readonly parentHistory: History, private readonly basePath: string) { + const parentPath = this.parentHistory.location.pathname; + if (!parentPath.startsWith(basePath)) { + throw new Error( + `Browser location [${parentPath}] is not currently in expected basePath [${basePath}]` + ); + } + + this.locationKeys.push(this.parentHistory.location.key); + this.setupHistoryListener(); + } + + /** + * Creates a `ScopedHistory` for a subpath of this `ScopedHistory`. Useful for applications that may have sub-apps + * that do not need access to the containing application's history. + * + * @param basePath the URL path scope for the sub history + */ + public createSubHistory = ( + basePath: string + ): ScopedHistory => { + return new ScopedHistory(this, basePath); + }; + + /** + * The number of entries in the history stack, including all entries forwards and backwards from the current location. + */ + public get length() { + this.verifyActive(); + return this.locationKeys.length; + } + + /** + * The current location of the history stack. + */ + public get location() { + this.verifyActive(); + return this.stripBasePath(this.parentHistory.location); + } + + /** + * The last action dispatched on the history stack. + */ + public get action() { + this.verifyActive(); + return this.parentHistory.action; + } + + /** + * Pushes a new location onto the history stack. If there are forward entries in the stack, they will be removed. + * + * @param pathOrLocation a string or location descriptor + * @param state + */ + public push = ( + pathOrLocation: Path | LocationDescriptorObject, + state?: HistoryLocationState + ): void => { + this.verifyActive(); + if (typeof pathOrLocation === 'string') { + this.parentHistory.push(this.prependBasePath(pathOrLocation), state); + } else { + this.parentHistory.push(this.prependBasePath(pathOrLocation)); + } + }; + + /** + * Replaces the current location in the history stack. Does not remove forward or backward entries. + * + * @param pathOrLocation a string or location descriptor + * @param state + */ + public replace = ( + pathOrLocation: Path | LocationDescriptorObject, + state?: HistoryLocationState + ): void => { + this.verifyActive(); + if (typeof pathOrLocation === 'string') { + this.parentHistory.replace(this.prependBasePath(pathOrLocation), state); + } else { + this.parentHistory.replace(this.prependBasePath(pathOrLocation)); + } + }; + + /** + * Send the user forward or backwards in the history stack. + * + * @param n number of positions in the stack to go. Negative numbers indicate number of entries backward, positive + * numbers for forwards. If passed 0, the current location will be reloaded. If `n` exceeds the number of + * entries available, this is a no-op. + */ + public go = (n: number): void => { + this.verifyActive(); + if (n === 0) { + this.parentHistory.go(n); + } else if (n < 0) { + if (this.currentLocationKeyIndex + 1 + n >= 1) { + this.parentHistory.go(n); + } + } else if (n <= this.currentLocationKeyIndex + this.locationKeys.length - 1) { + this.parentHistory.go(n); + } + // no-op if no conditions above are met + }; + + /** + * Send the user one location back in the history stack. Equivalent to calling + * {@link ScopedHistory.go | ScopedHistory.go(-1)}. If no more entries are available backwards, this is a no-op. + */ + public goBack = () => { + this.verifyActive(); + this.go(-1); + }; + + /** + * Send the user one location forward in the history stack. Equivalent to calling + * {@link ScopedHistory.go | ScopedHistory.go(1)}. If no more entries are available forwards, this is a no-op. + */ + public goForward = () => { + this.verifyActive(); + this.go(1); + }; + + /** + * Not supported. Use {@link AppMountParameters.onAppLeave}. + * + * @remarks + * We prefer that applications use the `onAppLeave` API because it supports a more graceful experience that prefers + * a modal when possible, falling back to a confirm dialog box in the beforeunload case. + */ + public block = ( + prompt?: boolean | string | TransitionPromptHook + ): UnregisterCallback => { + throw new Error( + `history.block is not supported. Please use the AppMountParams.onAppLeave API.` + ); + }; + + /** + * Adds a listener for location updates. + * + * @param listener a function that receives location updates. + * @returns an function to unsubscribe the listener. + */ + public listen = ( + listener: (location: Location, action: Action) => void + ): UnregisterCallback => { + this.verifyActive(); + this.listeners.add(listener); + return () => { + this.listeners.delete(listener); + }; + }; + + /** + * Creates an href (string) to the location. + * + * @param location + */ + public createHref = (location: LocationDescriptorObject): Href => { + this.verifyActive(); + return this.parentHistory.createHref(location); + }; + + private prependBasePath(path: Path): Path; + private prependBasePath( + location: LocationDescriptorObject + ): LocationDescriptorObject; + /** + * Prepends the scoped base path to the Path or Location + */ + private prependBasePath( + pathOrLocation: Path | LocationDescriptorObject + ): Path | LocationDescriptorObject { + if (typeof pathOrLocation === 'string') { + return this.prependBasePathToString(pathOrLocation); + } else { + return { + ...pathOrLocation, + pathname: + pathOrLocation.pathname !== undefined + ? this.prependBasePathToString(pathOrLocation.pathname) + : undefined, + }; + } + } + + /** + * Prepends the base path to string. + */ + private prependBasePathToString(path: string): string { + path = path.startsWith('/') ? path.slice(1) : path; + return path.length ? `${this.basePath}/${path}` : this.basePath; + } + + /** + * Removes the base path from a location. + */ + private stripBasePath(location: Location): Location { + return { + ...location, + pathname: location.pathname.replace(new RegExp(`^${this.basePath}`), ''), + }; + } + + /** Called on each public method to ensure that we have not fallen out of scope yet. */ + private verifyActive() { + if (!this.isActive) { + throw new Error( + `ScopedHistory instance has fell out of navigation scope for basePath: ${this.basePath}` + ); + } + } + + /** + * Sets up the listener on the parent history instance used to follow navigation updates and track our internal + * state. Also forwards events to child listeners with the base path stripped from the location. + */ + private setupHistoryListener() { + const unlisten = this.parentHistory.listen((location, action) => { + // If the user navigates outside the scope of this basePath, tear it down. + if (!location.pathname.startsWith(this.basePath)) { + unlisten(); + this.isActive = false; + return; + } + + /** + * Track location keys using the same algorithm the browser uses internally. + * - On PUSH, remove all items that came after the current location and append the new location. + * - On POP, set the current location, but do not change the entries. + * - On REPLACE, override the location for the current index with the new location. + */ + if (action === 'PUSH') { + this.locationKeys = [ + ...this.locationKeys.slice(0, this.currentLocationKeyIndex + 1), + location.key, + ]; + this.currentLocationKeyIndex = this.locationKeys.indexOf(location.key); // should always be the last index + } else if (action === 'POP') { + this.currentLocationKeyIndex = this.locationKeys.indexOf(location.key); + } else if (action === 'REPLACE') { + this.locationKeys[this.currentLocationKeyIndex] = location.key; + } else { + throw new Error(`Unrecognized history action: ${action}`); + } + + [...this.listeners].forEach(listener => { + listener(this.stripBasePath(location), action); + }); + }); + } +} diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts index 977bb7a52da22..facb818c60ff9 100644 --- a/src/core/public/application/types.ts +++ b/src/core/public/application/types.ts @@ -32,6 +32,7 @@ import { IUiSettingsClient } from '../ui_settings'; import { RecursiveReadonly } from '../../utils'; import { SavedObjectsStart } from '../saved_objects'; import { AppCategory } from '../../types'; +import { ScopedHistory } from './scoped_history'; /** @public */ export interface AppBase { @@ -199,7 +200,7 @@ export type AppUpdater = (app: AppBase) => Partial | undefin * Extension of {@link AppBase | common app properties} with the mount function. * @public */ -export interface App extends AppBase { +export interface App extends AppBase { /** * A mount function called when the user navigates to this app's route. May have signature of {@link AppMount} or * {@link AppMountDeprecated}. @@ -208,7 +209,7 @@ export interface App extends AppBase { * When function has two arguments, it will be called with a {@link AppMountContext | context} as the first argument. * This behavior is **deprecated**, and consumers should instead use {@link CoreSetup.getStartServices}. */ - mount: AppMount | AppMountDeprecated; + mount: AppMount | AppMountDeprecated; /** * Hide the UI chrome when the application is mounted. Defaults to `false`. @@ -240,7 +241,9 @@ export interface LegacyApp extends AppBase { * * @public */ -export type AppMount = (params: AppMountParameters) => AppUnmount | Promise; +export type AppMount = ( + params: AppMountParameters +) => AppUnmount | Promise; /** * A mount function called when the user navigates to this app's route. @@ -256,9 +259,9 @@ export type AppMount = (params: AppMountParameters) => AppUnmount | Promise = ( context: AppMountContext, - params: AppMountParameters + params: AppMountParameters ) => AppUnmount | Promise; /** @@ -304,16 +307,65 @@ export interface AppMountContext { } /** @public */ -export interface AppMountParameters { +export interface AppMountParameters { /** * The container element to render the application into. */ element: HTMLElement; + /** + * A scoped history instance for your application. Should be used to wire up + * your applications Router. + * + * @example + * How to configure react-router with a base path: + * + * ```ts + * // inside your plugin's setup function + * export class MyPlugin implements Plugin { + * setup({ application }) { + * application.register({ + * id: 'my-app', + * appRoute: '/my-app', + * async mount(params) { + * const { renderApp } = await import('./application'); + * return renderApp(params); + * }, + * }); + * } + * } + * ``` + * + * ```ts + * // application.tsx + * import React from 'react'; + * import ReactDOM from 'react-dom'; + * import { Router, Route } from 'react-router-dom'; + * + * import { CoreStart, AppMountParameters } from 'src/core/public'; + * import { MyPluginDepsStart } from './plugin'; + * + * export renderApp = ({ element, history }: AppMountParameters) => { + * ReactDOM.render( + * // pass `appBasePath` to `basename` + * + * + * , + * element + * ); + * + * return () => ReactDOM.unmountComponentAtNode(element); + * } + * ``` + */ + history: ScopedHistory; + /** * The route path for configuring navigation to the application. * This string should not include the base path from HTTP. * + * @deprecated Use {@link AppMountParameters.history} instead. + * * @example * * How to configure react-router with a base path: @@ -340,10 +392,10 @@ export interface AppMountParameters { * import ReactDOM from 'react-dom'; * import { BrowserRouter, Route } from 'react-router-dom'; * - * import { CoreStart, AppMountParams } from 'src/core/public'; + * import { CoreStart, AppMountParameters } from 'src/core/public'; * import { MyPluginDepsStart } from './plugin'; * - * export renderApp = ({ appBasePath, element }: AppMountParams) => { + * export renderApp = ({ appBasePath, element }: AppMountParameters) => { * ReactDOM.render( * // pass `appBasePath` to `basename` * @@ -498,8 +550,9 @@ export interface ApplicationSetup { /** * Register an mountable application to the system. * @param app - an {@link App} + * @typeParam HistoryLocationState - shape of the `History` state on {@link AppMountParameters.history}, defaults to `unknown`. */ - register(app: App): void; + register(app: App): void; /** * Register an application updater that can be used to change the {@link AppUpdatableFields} fields @@ -551,7 +604,10 @@ export interface InternalApplicationSetup extends Pick( + plugin: PluginOpaqueId, + app: App + ): void; /** * Register metadata about legacy applications. Legacy apps will not be mounted when navigated to. diff --git a/src/core/public/application/ui/app_container.test.tsx b/src/core/public/application/ui/app_container.test.tsx index a46243a2da493..c538227e8f098 100644 --- a/src/core/public/application/ui/app_container.test.tsx +++ b/src/core/public/application/ui/app_container.test.tsx @@ -22,6 +22,8 @@ import { mount } from 'enzyme'; import { AppContainer } from './app_container'; import { Mounter, AppMountParameters, AppStatus } from '../types'; +import { createMemoryHistory } from 'history'; +import { ScopedHistory } from '../scoped_history'; describe('AppContainer', () => { const appId = 'someApp'; @@ -60,10 +62,15 @@ describe('AppContainer', () => { const wrapper = mount( + // Create a history using the appPath as the current location + new ScopedHistory(createMemoryHistory({ initialEntries: [appPath] }), appPath) + } /> ); diff --git a/src/core/public/application/ui/app_container.tsx b/src/core/public/application/ui/app_container.tsx index 885157843e7df..e12a0f2cf2fcd 100644 --- a/src/core/public/application/ui/app_container.tsx +++ b/src/core/public/application/ui/app_container.tsx @@ -28,18 +28,24 @@ import React, { import { AppLeaveHandler, AppStatus, AppUnmount, Mounter } from '../types'; import { AppNotFound } from './app_not_found_screen'; +import { ScopedHistory } from '../scoped_history'; interface Props { + /** Path application is mounted on without the global basePath */ + appPath: string; appId: string; mounter?: Mounter; appStatus: AppStatus; setAppLeaveHandler: (appId: string, handler: AppLeaveHandler) => void; + createScopedHistory: (appUrl: string) => ScopedHistory; } export const AppContainer: FunctionComponent = ({ mounter, appId, + appPath, setAppLeaveHandler, + createScopedHistory, appStatus, }: Props) => { const [appNotFound, setAppNotFound] = useState(false); @@ -67,6 +73,7 @@ export const AppContainer: FunctionComponent = ({ unmountRef.current = (await mounter.mount({ appBasePath: mounter.appBasePath, + history: createScopedHistory(appPath), element: elementRef.current!, onAppLeave: handler => setAppLeaveHandler(appId, handler), })) || null; @@ -75,7 +82,7 @@ export const AppContainer: FunctionComponent = ({ mount(); return unmount; - }, [appId, appStatus, mounter, setAppLeaveHandler]); + }, [appId, appStatus, mounter, createScopedHistory, setAppLeaveHandler, appPath]); return ( diff --git a/src/core/public/application/ui/app_router.tsx b/src/core/public/application/ui/app_router.tsx index 50e5f5ee1bd62..61c8bc3cadae5 100644 --- a/src/core/public/application/ui/app_router.tsx +++ b/src/core/public/application/ui/app_router.tsx @@ -17,7 +17,7 @@ * under the License. */ -import React, { FunctionComponent } from 'react'; +import React, { FunctionComponent, useMemo } from 'react'; import { Route, RouteComponentProps, Router, Switch } from 'react-router-dom'; import { History } from 'history'; import { Observable } from 'rxjs'; @@ -25,6 +25,7 @@ import { useObservable } from 'react-use'; import { AppLeaveHandler, AppStatus, Mounter } from '../types'; import { AppContainer } from './app_container'; +import { ScopedHistory } from '../scoped_history'; interface Props { mounters: Map; @@ -44,6 +45,11 @@ export const AppRouter: FunctionComponent = ({ appStatuses$, }) => { const appStatuses = useObservable(appStatuses$, new Map()); + const createScopedHistory = useMemo( + () => (appPath: string) => new ScopedHistory(history, appPath), + [history] + ); + return ( @@ -56,12 +62,12 @@ export const AppRouter: FunctionComponent = ({ ( + render={({ match: { url } }) => ( )} />, @@ -72,6 +78,7 @@ export const AppRouter: FunctionComponent = ({ render={({ match: { params: { appId }, + url, }, }: RouteComponentProps) => { // Find the mounter including legacy mounters with subapps: @@ -81,10 +88,11 @@ export const AppRouter: FunctionComponent = ({ return ( ); }} diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 6d756e36d7379..483d4dbfdf7c5 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -108,6 +108,7 @@ export { AppNavLinkStatus, AppUpdatableFields, AppUpdater, + ScopedHistory, } from './application'; export { diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts index 3301d71e2cdaf..8ea672890ca29 100644 --- a/src/core/public/mocks.ts +++ b/src/core/public/mocks.ts @@ -41,6 +41,7 @@ export { notificationServiceMock } from './notifications/notifications_service.m export { overlayServiceMock } from './overlays/overlay_service.mock'; export { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock'; export { savedObjectsServiceMock } from './saved_objects/saved_objects_service.mock'; +export { scopedHistoryMock } from './application/scoped_history.mock'; function createCoreSetupMock({ basePath = '' } = {}) { const mock = { diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index ba1988b857385..cd956eb17531a 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -4,25 +4,30 @@ ```ts +import { Action } from 'history'; import { Breadcrumb } from '@elastic/eui'; import { EuiButtonEmptyProps } from '@elastic/eui'; import { EuiConfirmModalProps } from '@elastic/eui'; import { EuiGlobalToastListToast } from '@elastic/eui'; import { ExclusiveUnion } from '@elastic/eui'; +import { History } from 'history'; import { IconType } from '@elastic/eui'; +import { Location } from 'history'; +import { LocationDescriptorObject } from 'history'; import { MaybePromise } from '@kbn/utility-types'; import { Observable } from 'rxjs'; import React from 'react'; import * as Rx from 'rxjs'; import { ShallowPromise } from '@kbn/utility-types'; import { UiSettingsParams as UiSettingsParams_2 } from 'src/core/server/types'; +import { UnregisterCallback } from 'history'; import { UserProvidedValues as UserProvidedValues_2 } from 'src/core/server/types'; // @public -export interface App extends AppBase { +export interface App extends AppBase { appRoute?: string; chromeless?: boolean; - mount: AppMount | AppMountDeprecated; + mount: AppMount | AppMountDeprecated; } // @public (undocumented) @@ -89,7 +94,7 @@ export type AppLeaveHandler = (factory: AppLeaveActionFactory) => AppLeaveAction // @public (undocumented) export interface ApplicationSetup { - register(app: App): void; + register(app: App): void; registerAppUpdater(appUpdater$: Observable): void; // @deprecated registerMountContext(contextName: T, provider: IContextProvider): void; @@ -112,7 +117,7 @@ export interface ApplicationStart { } // @public -export type AppMount = (params: AppMountParameters) => AppUnmount | Promise; +export type AppMount = (params: AppMountParameters) => AppUnmount | Promise; // @public @deprecated export interface AppMountContext { @@ -133,12 +138,14 @@ export interface AppMountContext { } // @public @deprecated -export type AppMountDeprecated = (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise; +export type AppMountDeprecated = (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise; // @public (undocumented) -export interface AppMountParameters { +export interface AppMountParameters { + // @deprecated appBasePath: string; element: HTMLElement; + history: ScopedHistory; onAppLeave: (handler: AppLeaveHandler) => void; } @@ -1175,6 +1182,23 @@ export interface SavedObjectsUpdateOptions { version?: string; } +// @public +export class ScopedHistory implements History { + constructor(parentHistory: History, basePath: string); + get action(): Action; + block: (prompt?: string | boolean | History.TransitionPromptHook | undefined) => UnregisterCallback; + createHref: (location: LocationDescriptorObject) => string; + createSubHistory: (basePath: string) => ScopedHistory; + go: (n: number) => void; + goBack: () => void; + goForward: () => void; + get length(): number; + listen: (listener: (location: Location, action: Action) => void) => UnregisterCallback; + get location(): Location; + push: (pathOrLocation: string | LocationDescriptorObject, state?: HistoryLocationState | undefined) => void; + replace: (pathOrLocation: string | LocationDescriptorObject, state?: HistoryLocationState | undefined) => void; + } + // @public export class SimpleSavedObject { constructor(client: SavedObjectsClientContract, { id, type, version, attributes, error, references, migrationVersion }: SavedObject); diff --git a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts index 90328003c8292..14564cfd9ee78 100644 --- a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts +++ b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts @@ -68,7 +68,13 @@ export class LocalApplicationService { isUnmounted = true; }); (async () => { - const params = { element, appBasePath: '', onAppLeave: () => undefined }; + const params = { + element, + appBasePath: '', + onAppLeave: () => undefined, + // TODO: adapt to use Core's ScopedHistory + history: {} as any, + }; unmountHandler = isAppMountDeprecated(app.mount) ? await app.mount({ core: npStart.core }, params) : await app.mount(params); diff --git a/src/legacy/ui/public/new_platform/new_platform.test.mocks.ts b/src/legacy/ui/public/new_platform/new_platform.test.mocks.ts index e660ad1f55840..f44efe17ef8ee 100644 --- a/src/legacy/ui/public/new_platform/new_platform.test.mocks.ts +++ b/src/legacy/ui/public/new_platform/new_platform.test.mocks.ts @@ -17,8 +17,15 @@ * under the License. */ +import { scopedHistoryMock } from '../../../../core/public/mocks'; + export const setRootControllerMock = jest.fn(); jest.doMock('ui/chrome', () => ({ setRootController: setRootControllerMock, })); + +export const historyMock = scopedHistoryMock.create(); +jest.doMock('../../../../core/public', () => ({ + ScopedHistory: jest.fn(() => historyMock), +})); diff --git a/src/legacy/ui/public/new_platform/new_platform.test.ts b/src/legacy/ui/public/new_platform/new_platform.test.ts index e050ffd5b530c..498f05457bba9 100644 --- a/src/legacy/ui/public/new_platform/new_platform.test.ts +++ b/src/legacy/ui/public/new_platform/new_platform.test.ts @@ -17,7 +17,9 @@ * under the License. */ -import { setRootControllerMock } from './new_platform.test.mocks'; +jest.mock('history'); + +import { setRootControllerMock, historyMock } from './new_platform.test.mocks'; import { legacyAppRegister, __reset__, __setup__ } from './new_platform'; import { coreMock } from '../../../../core/public/mocks'; @@ -63,6 +65,7 @@ describe('ui/new_platform', () => { element: elementMock[0], appBasePath: '/test/base/path/app/test', onAppLeave: expect.any(Function), + history: historyMock, }); }); @@ -84,6 +87,7 @@ describe('ui/new_platform', () => { element: elementMock[0], appBasePath: '/test/base/path/app/test', onAppLeave: expect.any(Function), + history: historyMock, }); }); diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts index b7994c7f68afb..00d76bc341322 100644 --- a/src/legacy/ui/public/new_platform/new_platform.ts +++ b/src/legacy/ui/public/new_platform/new_platform.ts @@ -20,7 +20,14 @@ import { IScope } from 'angular'; import { UiActionsStart, UiActionsSetup } from 'src/plugins/ui_actions/public'; import { IEmbeddableStart, IEmbeddableSetup } from 'src/plugins/embeddable/public'; -import { LegacyCoreSetup, LegacyCoreStart, App, AppMountDeprecated } from '../../../../core/public'; +import { createBrowserHistory } from 'history'; +import { + LegacyCoreSetup, + LegacyCoreStart, + App, + AppMountDeprecated, + ScopedHistory, +} from '../../../../core/public'; import { Plugin as DataPlugin } from '../../../../plugins/data/public'; import { Plugin as ExpressionsPlugin } from '../../../../plugins/expressions/public'; import { @@ -126,7 +133,7 @@ let legacyAppRegistered = false; * Exported for testing only. Use `npSetup.core.application.register` in legacy apps. * @internal */ -export const legacyAppRegister = (app: App) => { +export const legacyAppRegister = (app: App) => { if (legacyAppRegistered) { throw new Error(`core.application.register may only be called once for legacy plugins.`); } @@ -137,9 +144,15 @@ export const legacyAppRegister = (app: App) => { // Root controller cannot return a Promise so use an internal async function and call it immediately (async () => { + const appRoute = app.appRoute || `/app/${app.id}`; + const appBasePath = npSetup.core.http.basePath.prepend(appRoute); const params = { element, - appBasePath: npSetup.core.http.basePath.prepend(`/app/${app.id}`), + appBasePath, + history: new ScopedHistory( + createBrowserHistory({ basename: npSetup.core.http.basePath.get() }), + appRoute + ), onAppLeave: () => undefined, }; const unmount = isAppMountDeprecated(app.mount) diff --git a/src/plugins/dev_tools/public/application.tsx b/src/plugins/dev_tools/public/application.tsx index a179be6946c76..2c21b451cb9f7 100644 --- a/src/plugins/dev_tools/public/application.tsx +++ b/src/plugins/dev_tools/public/application.tsx @@ -91,7 +91,13 @@ function DevToolsWrapper({ if (mountedTool.current) { mountedTool.current.unmountHandler(); } - const params = { element, appBasePath: '', onAppLeave: () => undefined }; + const params = { + element, + appBasePath: '', + onAppLeave: () => undefined, + // TODO: adapt to use Core's ScopedHistory + history: {} as any, + }; const unmountHandler = isAppMountDeprecated(activeDevTool.mount) ? await activeDevTool.mount(appMountContext, params) : await activeDevTool.mount(params); diff --git a/test/plugin_functional/plugins/core_plugin_a/public/application.tsx b/test/plugin_functional/plugins/core_plugin_a/public/application.tsx index 7c1406f5b20c3..abea970749cbc 100644 --- a/test/plugin_functional/plugins/core_plugin_a/public/application.tsx +++ b/test/plugin_functional/plugins/core_plugin_a/public/application.tsx @@ -17,9 +17,10 @@ * under the License. */ +import { History } from 'history'; import React from 'react'; import ReactDOM from 'react-dom'; -import { BrowserRouter as Router, Route, withRouter, RouteComponentProps } from 'react-router-dom'; +import { Router, Route, withRouter, RouteComponentProps } from 'react-router-dom'; import { EuiPage, @@ -115,8 +116,8 @@ const Nav = withRouter(({ history, navigateToApp }: NavProps) => ( /> )); -const FooApp = ({ basename, context }: { basename: string; context: AppMountContext }) => ( - +const FooApp = ({ history, context }: { history: History; context: AppMountContext }) => ( +
@@ -64,9 +66,11 @@ exports[`FieldName renders a number field by providing a field record, useShortD class="euiFlexItem eui-textTruncate" > - test.test.test + + test.test.test +

ufUdkMWXl>|PBtPjqT>MV4p+N>=w`{+aU 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

@@ -100,9 +104,11 @@ exports[`FieldName renders a string field by providing fieldType and fieldName 1 class="euiFlexItem eui-textTruncate" > - test + + test +
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx index 54e1c1706a856..e2aa33179f632 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx @@ -18,7 +18,7 @@ */ import React from 'react'; import classNames from 'classnames'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; import { FieldIcon, FieldIconProps } from '../../../../../../../../../plugins/kibana_react/public'; import { shortenDottedString } from '../../../../../../../../../plugins/data/common/utils'; @@ -64,7 +64,14 @@ export function FieldName({ field, fieldName, fieldType, useShortDots, fieldIcon />
- {displayName} + + {displayName} + ); From 92840fe2181ccb43d032df94c1a277f49c52a503 Mon Sep 17 00:00:00 2001 From: Maryia Lapata Date: Thu, 27 Feb 2020 10:35:44 +0300 Subject: [PATCH 119/123] [NP] Import saved objects styles directly (#58208) * Import styles for saved objects * Rename index.scss Co-authored-by: Elastic Machine --- src/legacy/ui/public/_index.scss | 1 - src/legacy/ui/public/saved_objects/_index.scss | 1 - src/plugins/saved_objects/public/{_index.scss => index.scss} | 0 src/plugins/saved_objects/public/plugin.ts | 2 ++ 4 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 src/legacy/ui/public/saved_objects/_index.scss rename src/plugins/saved_objects/public/{_index.scss => index.scss} (100%) diff --git a/src/legacy/ui/public/_index.scss b/src/legacy/ui/public/_index.scss index e990ba2a46de5..3c3067776a161 100644 --- a/src/legacy/ui/public/_index.scss +++ b/src/legacy/ui/public/_index.scss @@ -15,7 +15,6 @@ @import './error_url_overflow/index'; @import './exit_full_screen/index'; @import './field_editor/index'; -@import './saved_objects/index'; @import './share/index'; @import './style_compile/index'; @import '../../../plugins/management/public/components/index'; diff --git a/src/legacy/ui/public/saved_objects/_index.scss b/src/legacy/ui/public/saved_objects/_index.scss deleted file mode 100644 index 89cda29f67744..0000000000000 --- a/src/legacy/ui/public/saved_objects/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../../../plugins/saved_objects/public/index'; diff --git a/src/plugins/saved_objects/public/_index.scss b/src/plugins/saved_objects/public/index.scss similarity index 100% rename from src/plugins/saved_objects/public/_index.scss rename to src/plugins/saved_objects/public/index.scss diff --git a/src/plugins/saved_objects/public/plugin.ts b/src/plugins/saved_objects/public/plugin.ts index e937c271b6faf..5092f7a0b7b33 100644 --- a/src/plugins/saved_objects/public/plugin.ts +++ b/src/plugins/saved_objects/public/plugin.ts @@ -19,6 +19,8 @@ import { Plugin } from 'src/core/public'; +import './index.scss'; + export class SavedObjectsPublicPlugin implements Plugin { public setup() {} public start() {} From 320e292ea8b32f397b59ec595af3822f37b11f1c Mon Sep 17 00:00:00 2001 From: patrykkopycinski Date: Thu, 27 Feb 2020 09:25:37 +0100 Subject: [PATCH 120/123] [SIEM] apollo@3 (#51926) --- package.json | 17 +- .../basic_optimization.test.ts | 1 - .../integration_tests/bundle_cache.test.ts | 1 - .../src/worker/webpack.config.ts | 2 +- packages/kbn-pm/dist/index.js | 26323 +--------------- .../siem/common/graphql/root/schema.gql.ts | 2 +- .../siem/common/graphql/shared/schema.gql.ts | 2 +- x-pack/legacy/plugins/siem/public/app/app.tsx | 20 +- .../drag_drop_context_wrapper.test.tsx | 4 +- .../drag_and_drop/draggable_wrapper.test.tsx | 4 +- .../drag_and_drop/droppable_wrapper.test.tsx | 4 +- .../components/event_details/columns.tsx | 4 +- .../components/event_details/helpers.tsx | 4 +- .../events_viewer/events_viewer.test.tsx | 11 +- .../events_viewer/events_viewer.tsx | 3 +- .../components/events_viewer/index.test.tsx | 7 +- .../siem/public/components/flyout/index.tsx | 13 +- .../__snapshots__/index.test.tsx.snap | 103 +- .../components/header_global/index.test.tsx | 7 +- .../public/components/header_global/index.tsx | 108 +- .../components/open_timeline/helpers.ts | 2 +- .../components/open_timeline/index.test.tsx | 115 +- .../public/components/open_timeline/index.tsx | 5 +- .../open_timeline/open_timeline.test.tsx | 2 +- .../open_timeline_modal/index.test.tsx | 8 +- .../open_timeline_modal/index.tsx | 44 +- .../open_timeline_modal_body.test.tsx | 2 +- .../open_timeline_modal_button.test.tsx | 7 +- .../timelines_table/actions_columns.test.tsx | 2 +- .../timelines_table/common_columns.test.tsx | 2 +- .../timelines_table/extended_columns.test.tsx | 2 +- .../icon_header_columns.test.tsx | 2 +- .../timelines_table/index.test.tsx | 2 +- .../hosts/first_last_seen_host/index.test.tsx | 12 +- .../page/hosts/first_last_seen_host/index.tsx | 68 +- .../__snapshots__/index.test.tsx.snap | 91 - .../page/hosts/hosts_table/index.test.tsx | 11 +- .../page/hosts/hosts_table/index.tsx | 4 - .../components/page/hosts/kpi_hosts/index.tsx | 4 +- .../network/network_dns_table/index.test.tsx | 2 +- .../network/network_http_table/index.test.tsx | 2 +- .../index.test.tsx | 2 +- .../network_top_n_flow_table/index.test.tsx | 2 +- .../page/network/tls_table/index.test.tsx | 2 +- .../page/network/users_table/index.test.tsx | 2 +- .../overview/overview_host/index.test.tsx | 11 +- .../overview/overview_network/index.test.tsx | 11 +- .../page/overview/overview_network/index.tsx | 10 +- .../components/recent_timelines/index.tsx | 6 +- .../public/components/search_bar/index.tsx | 2 +- .../public/components/stat_items/index.tsx | 10 +- .../components/super_date_picker/index.tsx | 2 +- .../components/timeline/body/helpers.test.ts | 4 +- .../__snapshots__/zeek_details.test.tsx.snap | 771 +- .../timeline/body/stateful_body.tsx | 3 +- .../timeline/fetch_kql_timeline.tsx | 12 +- .../components/timeline/footer/index.tsx | 3 - .../components/timeline/header/index.tsx | 18 +- .../public/components/timeline/helpers.tsx | 130 +- .../siem/public/components/timeline/index.tsx | 74 +- .../timeline/search_or_filter/index.tsx | 2 +- .../components/timeline/timeline.test.tsx | 2 +- .../public/components/timeline/timeline.tsx | 31 +- .../components/url_state/index.test.tsx | 29 +- .../public/components/url_state/index.tsx | 2 +- .../url_state/index_mocked.test.tsx | 17 +- .../siem/public/components/url_state/types.ts | 5 +- .../components/url_state/use_url_state.tsx | 2 +- .../authentications/index.gql_query.ts | 2 +- .../containers/authentications/index.tsx | 11 +- .../rules/fetch_index_patterns.test.tsx | 4 +- .../rules/fetch_index_patterns.tsx | 2 +- .../public/containers/errors/index.test.tsx | 3 +- .../events/last_event_time/index.ts | 88 +- .../last_event_time.gql_query.ts | 2 +- .../containers/events/last_event_time/mock.ts | 11 +- .../public/containers/global_time/index.tsx | 71 +- .../plugins/siem/public/containers/helpers.ts | 4 +- .../first_last_seen.gql_query.ts | 2 +- .../containers/hosts/first_last_seen/index.ts | 11 +- .../containers/hosts/first_last_seen/mock.ts | 10 +- .../containers/hosts/hosts_table.gql_query.ts | 2 +- .../siem/public/containers/hosts/index.tsx | 10 +- .../hosts/overview/host_overview.gql_query.ts | 2 +- .../containers/hosts/overview/index.tsx | 15 +- .../containers/ip_overview/index.gql_query.ts | 2 +- .../public/containers/ip_overview/index.tsx | 12 +- ...index.gql_query.tsx => index.gql_query.ts} | 2 +- .../containers/kpi_host_details/index.tsx | 12 +- .../containers/kpi_hosts/index.gql_query.ts | 2 +- .../public/containers/kpi_hosts/index.tsx | 12 +- .../containers/kpi_network/index.gql_query.ts | 2 +- .../public/containers/kpi_network/index.tsx | 12 +- .../matrix_histogram/index.gql_query.ts | 2 +- .../matrix_histogram/index.test.tsx | 5 +- .../containers/matrix_histogram/index.ts | 3 +- .../containers/network_dns/index.gql_query.ts | 2 +- .../public/containers/network_dns/index.tsx | 10 +- .../network_http/index.gql_query.ts | 2 +- .../public/containers/network_http/index.tsx | 10 +- .../network_top_countries/index.gql_query.ts | 2 +- .../network_top_countries/index.tsx | 10 +- .../network_top_n_flow/index.gql_query.ts | 2 +- .../containers/network_top_n_flow/index.tsx | 10 +- .../overview/overview_host/index.gql_query.ts | 2 +- .../overview/overview_host/index.tsx | 64 +- .../overview_network/index.gql_query.ts | 2 +- .../overview/overview_network/index.tsx | 12 +- .../siem/public/containers/query_template.tsx | 8 +- .../containers/query_template_paginated.tsx | 11 +- .../containers/source/index.gql_query.ts | 2 +- .../public/containers/source/index.test.tsx | 44 +- .../siem/public/containers/source/index.tsx | 127 +- .../timeline/all/index.gql_query.ts | 2 +- .../public/containers/timeline/all/index.tsx | 11 +- .../timeline/delete/persist.gql_query.ts | 2 +- .../timeline/details/index.gql_query.ts | 2 +- .../containers/timeline/details/index.tsx | 14 +- .../timeline/favorite/persist.gql_query.ts | 2 +- .../containers/timeline/index.gql_query.ts | 2 +- .../siem/public/containers/timeline/index.tsx | 16 +- .../timeline/notes/persist.gql_query.ts | 2 +- .../timeline/one/index.gql_query.ts | 2 +- .../containers/timeline/persist.gql_query.ts | 2 +- .../pinned_event/persist.gql_query.ts | 2 +- .../public/containers/tls/index.gql_query.ts | 2 +- .../siem/public/containers/tls/index.tsx | 10 +- .../uncommon_processes/index.gql_query.ts | 2 +- .../containers/uncommon_processes/index.tsx | 11 +- .../containers/users/index.gql_query.ts | 2 +- .../siem/public/containers/users/index.tsx | 18 +- .../siem/public/graphql/introspection.json | 12556 -------- .../plugins/siem/public/graphql/types.ts | 5943 ---- .../plugins/siem/public/graphql/types.tsx | 5314 ++++ .../siem/public/lib/compose/helpers.test.ts | 25 +- .../siem/public/lib/compose/helpers.ts | 12 +- .../public/lib/compose/kibana_compose.tsx | 21 +- x-pack/legacy/plugins/siem/public/lib/lib.ts | 3 +- .../siem/public/mock/test_providers.tsx | 7 +- .../siem/public/mock/timeline_results.ts | 10 +- .../components/signals/default_config.tsx | 4 +- .../components/signals/index.tsx | 2 +- .../components/signals/types.ts | 4 +- .../detection_engine/detection_engine.tsx | 166 +- .../detection_engine/rules/details/index.tsx | 291 +- .../plugins/siem/public/pages/home/index.tsx | 151 +- .../pages/hosts/details/details_tabs.test.tsx | 12 +- .../pages/hosts/details/details_tabs.tsx | 1 - .../siem/public/pages/hosts/details/index.tsx | 216 +- .../siem/public/pages/hosts/hosts.test.tsx | 5 +- .../plugins/siem/public/pages/hosts/hosts.tsx | 152 +- .../siem/public/pages/hosts/hosts_tabs.tsx | 39 +- .../plugins/siem/public/pages/hosts/index.tsx | 116 +- .../navigation/events_query_tab_body.tsx | 4 +- .../hosts/navigation/hosts_query_tab_body.tsx | 2 - .../public/pages/hosts/navigation/types.ts | 3 +- .../plugins/siem/public/pages/hosts/types.ts | 2 - .../siem/public/pages/network/index.tsx | 111 +- .../__snapshots__/index.test.tsx.snap | 65 +- .../pages/network/ip_details/index.test.tsx | 72 +- .../public/pages/network/ip_details/index.tsx | 305 +- .../public/pages/network/network.test.tsx | 5 +- .../siem/public/pages/network/network.tsx | 176 +- .../pages/overview/event_counts/index.tsx | 28 +- .../siem/public/pages/overview/index.tsx | 4 +- .../public/pages/overview/overview.test.tsx | 5 +- .../siem/public/pages/overview/overview.tsx | 167 +- .../public/pages/overview/sidebar/sidebar.tsx | 4 +- .../siem/public/pages/timelines/index.tsx | 39 +- .../public/pages/timelines/timelines_page.tsx | 48 - .../public/store/timeline/epic_favorite.ts | 3 +- .../siem/public/store/timeline/epic_note.ts | 3 +- .../store/timeline/epic_pinned_event.ts | 3 +- .../siem/public/utils/apollo_context.ts | 19 - .../siem/public/utils/route/spy_routes.tsx | 3 +- .../plugins/siem/scripts/combined_schema.ts | 2 +- .../scripts/generate_types_from_graphql.js | 275 +- .../graphql/authentications/resolvers.ts | 9 +- .../graphql/authentications/schema.gql.ts | 2 +- .../siem/server/graphql/ecs/schema.gql.ts | 2 +- .../siem/server/graphql/events/resolvers.ts | 24 +- .../siem/server/graphql/events/schema.gql.ts | 2 +- .../siem/server/graphql/hosts/resolvers.ts | 23 +- .../siem/server/graphql/hosts/schema.gql.ts | 2 +- .../server/graphql/ip_details/resolvers.ts | 16 +- .../server/graphql/ip_details/schema.gql.ts | 2 +- .../server/graphql/kpi_hosts/resolvers.ts | 16 +- .../server/graphql/kpi_hosts/schema.gql.ts | 2 +- .../server/graphql/kpi_network/resolvers.ts | 9 +- .../server/graphql/kpi_network/schema.gql.ts | 2 +- .../graphql/matrix_histogram/resolvers.ts | 9 +- .../graphql/matrix_histogram/schema.gql.ts | 2 +- .../siem/server/graphql/network/resolvers.ts | 30 +- .../siem/server/graphql/network/schema.gql.ts | 2 +- .../siem/server/graphql/note/resolvers.ts | 38 +- .../siem/server/graphql/note/schema.gql.ts | 2 +- .../siem/server/graphql/overview/resolvers.ts | 16 +- .../server/graphql/overview/schema.gql.ts | 2 +- .../server/graphql/pinned_event/resolvers.ts | 25 +- .../server/graphql/pinned_event/schema.gql.ts | 2 +- .../graphql/scalar_date/resolvers.test.ts | 4 +- .../server/graphql/scalar_date/schema.gql.ts | 2 +- .../graphql/scalar_to_any/schema.gql.ts | 2 +- .../scalar_to_boolean_array/schema.gql.ts | 2 +- .../scalar_to_date_array/schema.gql.ts | 2 +- .../scalar_to_number_array/schema.gql.ts | 2 +- .../server/graphql/source_status/resolvers.ts | 16 +- .../graphql/source_status/schema.gql.ts | 2 +- .../siem/server/graphql/sources/resolvers.ts | 56 +- .../siem/server/graphql/sources/schema.gql.ts | 2 +- .../siem/server/graphql/timeline/resolvers.ts | 28 +- .../server/graphql/timeline/schema.gql.ts | 2 +- .../siem/server/graphql/tls/resolvers.ts | 9 +- .../siem/server/graphql/tls/schema.gql.ts | 2 +- .../plugins/siem/server/graphql/types.ts | 12351 +++----- .../graphql/uncommon_processes/resolvers.ts | 9 +- .../graphql/uncommon_processes/schema.gql.ts | 2 +- .../siem/server/graphql/who_am_i/resolvers.ts | 9 +- .../server/graphql/who_am_i/schema.gql.ts | 2 +- .../legacy/plugins/siem/server/init_server.ts | 2 +- .../siem/server/lib/framework/types.ts | 6 +- .../siem/server/utils/typed_resolvers.ts | 111 - x-pack/package.json | 25 +- .../apis/siem/feature_controls.ts | 2 +- .../apis/siem/saved_objects/notes.ts | 2 +- .../apis/siem/saved_objects/timeline.ts | 2 +- .../services/siem_graphql_client.ts | 11 +- yarn.lock | 1734 +- 228 files changed, 14193 insertions(+), 55777 deletions(-) rename x-pack/legacy/plugins/siem/public/containers/kpi_host_details/{index.gql_query.tsx => index.gql_query.ts} (97%) delete mode 100644 x-pack/legacy/plugins/siem/public/graphql/introspection.json delete mode 100644 x-pack/legacy/plugins/siem/public/graphql/types.ts create mode 100644 x-pack/legacy/plugins/siem/public/graphql/types.tsx delete mode 100644 x-pack/legacy/plugins/siem/public/pages/timelines/timelines_page.tsx delete mode 100644 x-pack/legacy/plugins/siem/public/utils/apollo_context.ts delete mode 100644 x-pack/legacy/plugins/siem/server/utils/typed_resolvers.ts diff --git a/package.json b/package.json index 0f04a2fba3b65..4ac4cbea96248 100644 --- a/package.json +++ b/package.json @@ -77,23 +77,31 @@ "url": "https://github.com/elastic/kibana.git" }, "resolutions": { + "**/@apollo/client": "^3.0.0-beta.37", + "**/@graphql-toolkit/common": "^0.9.7", + "**/@graphql-toolkit/core": "^0.9.7", + "**/@graphql-toolkit/graphql-file-loader": "^0.9.7", + "**/@graphql-toolkit/json-file-loader": "^0.9.7", + "**/@graphql-toolkit/schema-merging": "^0.9.7", + "**/@graphql-toolkit/url-loader": "^0.9.7", "**/@types/node": "10.12.27", "**/@types/react": "^16.9.19", "**/@types/react-router": "^5.1.3", "**/@types/hapi": "^17.0.18", "**/@types/angular": "^1.6.56", "**/@types/hoist-non-react-statics": "^3.3.1", - "**/typescript": "3.7.2", - "**/graphql-toolkit/lodash": "^4.17.13", + "**/apollo-link": "^1.2.13", + "**/deepmerge": "^4.2.2", + "**/fast-deep-equal": "^3.1.1", + "**/fast-glob": "3.1.1", "**/hoist-non-react-statics": "^3.3.2", "**/isomorphic-git/**/base64-js": "^1.2.1", "**/image-diff/gm/debug": "^2.6.9", "**/react-dom": "^16.12.0", "**/react": "^16.12.0", "**/react-test-renderer": "^16.12.0", - "**/deepmerge": "^4.2.2", "**/serialize-javascript": "^2.1.1", - "**/fast-deep-equal": "^3.1.1" + "**/typescript": "3.7.2" }, "workspaces": { "packages": [ @@ -325,7 +333,6 @@ "@types/getopts": "^2.0.1", "@types/glob": "^7.1.1", "@types/globby": "^8.0.0", - "@types/graphql": "^0.13.2", "@types/hapi": "^17.0.18", "@types/hapi-auth-cookie": "^9.1.0", "@types/has-ansi": "^3.0.0", diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts index fec31cbe40dfe..3d9393fd2d005 100644 --- a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -38,7 +38,6 @@ beforeAll(async () => { await cpy('**/*', MOCK_REPO_DIR, { cwd: MOCK_REPO_SRC, parents: true, - deep: true, }); }); diff --git a/packages/kbn-optimizer/src/integration_tests/bundle_cache.test.ts b/packages/kbn-optimizer/src/integration_tests/bundle_cache.test.ts index 1bfd8d3fd073a..3cddbfc53c1b9 100644 --- a/packages/kbn-optimizer/src/integration_tests/bundle_cache.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/bundle_cache.test.ts @@ -44,7 +44,6 @@ beforeEach(async () => { await cpy('**/*', MOCK_REPO_DIR, { cwd: MOCK_REPO_SRC, parents: true, - deep: true, }); }); diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 3c6ae78bc4d91..9ca0ad5811ef8 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -217,7 +217,7 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) { }, resolve: { - extensions: ['.js', '.ts', '.tsx', '.json'], + extensions: ['.mjs', '.js', '.ts', '.tsx', '.json'], alias: { tinymath: require.resolve('tinymath/lib/tinymath.es5.js'), }, diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index fe0491870e4bd..99b4b82a7e99b 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -94,7 +94,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _cli__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "run", function() { return _cli__WEBPACK_IMPORTED_MODULE_0__["run"]; }); -/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(704); +/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(705); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildProductionProjects"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); @@ -152,7 +152,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(16); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _commands__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(17); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(689); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(690); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(34); /* * Licensed to Elasticsearch B.V. under one or more contributor @@ -2507,8 +2507,8 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "commands", function() { return commands; }); /* harmony import */ var _bootstrap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(18); /* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(586); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(686); -/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(687); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(687); +/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(688); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -67704,7 +67704,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(587); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(675); +/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(676); /* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(ora__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(16); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); @@ -67813,12 +67813,12 @@ const {promisify} = __webpack_require__(29); const path = __webpack_require__(16); const globby = __webpack_require__(588); const isGlob = __webpack_require__(605); -const slash = __webpack_require__(666); +const slash = __webpack_require__(667); const gracefulFs = __webpack_require__(22); -const isPathCwd = __webpack_require__(668); -const isPathInside = __webpack_require__(669); -const rimraf = __webpack_require__(670); -const pMap = __webpack_require__(671); +const isPathCwd = __webpack_require__(669); +const isPathInside = __webpack_require__(670); +const rimraf = __webpack_require__(671); +const pMap = __webpack_require__(672); const rimrafP = promisify(rimraf); @@ -67942,9 +67942,9 @@ const arrayUnion = __webpack_require__(589); const merge2 = __webpack_require__(590); const glob = __webpack_require__(591); const fastGlob = __webpack_require__(596); -const dirGlob = __webpack_require__(662); -const gitignore = __webpack_require__(664); -const {FilterStream, UniqueStream} = __webpack_require__(667); +const dirGlob = __webpack_require__(663); +const gitignore = __webpack_require__(665); +const {FilterStream, UniqueStream} = __webpack_require__(668); const DEFAULT_FILTER = () => false; @@ -69831,10 +69831,10 @@ function childrenIgnored (self, path) { "use strict"; const taskManager = __webpack_require__(597); -const async_1 = __webpack_require__(625); -const stream_1 = __webpack_require__(658); -const sync_1 = __webpack_require__(659); -const settings_1 = __webpack_require__(661); +const async_1 = __webpack_require__(626); +const stream_1 = __webpack_require__(659); +const sync_1 = __webpack_require__(660); +const settings_1 = __webpack_require__(662); const utils = __webpack_require__(598); function FastGlob(source, options) { try { @@ -69846,6 +69846,8 @@ function FastGlob(source, options) { const works = getWorks(source, async_1.default, options); return Promise.all(works).then(utils.array.flatten); } +// https://github.com/typescript-eslint/typescript-eslint/issues/60 +// eslint-disable-next-line no-redeclare (function (FastGlob) { function sync(source, options) { assertPatternsInput(source); @@ -69871,6 +69873,17 @@ function FastGlob(source, options) { return taskManager.generate(patterns, settings); } FastGlob.generateTasks = generateTasks; + function isDynamicPattern(source, options) { + assertPatternsInput(source); + const settings = new settings_1.default(options); + return utils.pattern.isDynamicPattern(source, settings); + } + FastGlob.isDynamicPattern = isDynamicPattern; + function escapePath(source) { + assertPatternsInput(source); + return utils.path.escape(source); + } + FastGlob.escapePath = escapePath; })(FastGlob || (FastGlob = {})); function getWorks(source, _Provider, options) { const patterns = [].concat(source); @@ -69886,7 +69899,6 @@ function assertPatternsInput(source) { throw new TypeError('Patterns must be a string or an array of strings'); } function isString(source) { - /* tslint:disable-next-line strict-type-predicates */ return typeof source === 'string'; } module.exports = FastGlob; @@ -69903,12 +69915,8 @@ const utils = __webpack_require__(598); function generate(patterns, settings) { const positivePatterns = getPositivePatterns(patterns); const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore); - /** - * When the `caseSensitiveMatch` option is disabled, all patterns must be marked as dynamic, because we cannot check - * filepath directly (without read directory). - */ - const staticPatterns = !settings.caseSensitiveMatch ? [] : positivePatterns.filter(utils.pattern.isStaticPattern); - const dynamicPatterns = !settings.caseSensitiveMatch ? positivePatterns : positivePatterns.filter(utils.pattern.isDynamicPattern); + const staticPatterns = positivePatterns.filter((pattern) => utils.pattern.isStaticPattern(pattern, settings)); + const dynamicPatterns = positivePatterns.filter((pattern) => utils.pattern.isDynamicPattern(pattern, settings)); const staticTasks = convertPatternsToTasks(staticPatterns, negativePatterns, /* dynamic */ false); const dynamicTasks = convertPatternsToTasks(dynamicPatterns, negativePatterns, /* dynamic */ true); return staticTasks.concat(dynamicTasks); @@ -69936,6 +69944,7 @@ function getNegativePatternsAsPositive(patterns, ignore) { } exports.getNegativePatternsAsPositive = getNegativePatternsAsPositive; function groupPatternsByBaseDirectory(patterns) { + const group = {}; return patterns.reduce((collection, pattern) => { const base = utils.pattern.getBaseDirectory(pattern); if (base in collection) { @@ -69945,7 +69954,7 @@ function groupPatternsByBaseDirectory(patterns) { collection[base] = [pattern]; } return collection; - }, {}); + }, group); } exports.groupPatternsByBaseDirectory = groupPatternsByBaseDirectory; function convertPatternGroupsToTasks(positive, negative, dynamic) { @@ -70046,6 +70055,7 @@ exports.createDirentFromStats = createDirentFromStats; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); +const UNESCAPED_GLOB_SYMBOLS_RE = /(\\?)([*?|(){}[\]]|^!|[@+!](?=\())/g; /** * Designed to work only with simple paths: `dir\\file`. */ @@ -70057,6 +70067,10 @@ function makeAbsolute(cwd, filepath) { return path.resolve(cwd, filepath); } exports.makeAbsolute = makeAbsolute; +function escape(pattern) { + return pattern.replace(UNESCAPED_GLOB_SYMBOLS_RE, '\\$2'); +} +exports.escape = escape; /***/ }), @@ -70068,15 +70082,36 @@ exports.makeAbsolute = makeAbsolute; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); const globParent = __webpack_require__(604); -const isGlob = __webpack_require__(605); const micromatch = __webpack_require__(607); const GLOBSTAR = '**'; -function isStaticPattern(pattern) { - return !isDynamicPattern(pattern); +const ESCAPE_SYMBOL = '\\'; +const COMMON_GLOB_SYMBOLS_RE = /[*?]|^!/; +const REGEX_CHARACTER_CLASS_SYMBOLS_RE = /\[.*]/; +const REGEX_GROUP_SYMBOLS_RE = /(?:^|[^@!*?+])\(.*\|.*\)/; +const GLOB_EXTENSION_SYMBOLS_RE = /[@!*?+]\(.*\)/; +const BRACE_EXPANSIONS_SYMBOLS_RE = /{.*(?:,|\.\.).*}/; +function isStaticPattern(pattern, options = {}) { + return !isDynamicPattern(pattern, options); } exports.isStaticPattern = isStaticPattern; -function isDynamicPattern(pattern) { - return isGlob(pattern, { strict: false }); +function isDynamicPattern(pattern, options = {}) { + /** + * When the `caseSensitiveMatch` option is disabled, all patterns must be marked as dynamic, because we cannot check + * filepath directly (without read directory). + */ + if (options.caseSensitiveMatch === false || pattern.includes(ESCAPE_SYMBOL)) { + return true; + } + if (COMMON_GLOB_SYMBOLS_RE.test(pattern) || REGEX_CHARACTER_CLASS_SYMBOLS_RE.test(pattern) || REGEX_GROUP_SYMBOLS_RE.test(pattern)) { + return true; + } + if (options.extglob !== false && GLOB_EXTENSION_SYMBOLS_RE.test(pattern)) { + return true; + } + if (options.braceExpansion !== false && BRACE_EXPANSIONS_SYMBOLS_RE.test(pattern)) { + return true; + } + return false; } exports.isDynamicPattern = isDynamicPattern; function convertToPositivePattern(pattern) { @@ -70104,11 +70139,11 @@ function getPositivePatterns(patterns) { } exports.getPositivePatterns = getPositivePatterns; function getBaseDirectory(pattern) { - return globParent(pattern); + return globParent(pattern, { flipBackslashes: false }); } exports.getBaseDirectory = getBaseDirectory; function hasGlobStar(pattern) { - return pattern.indexOf(GLOBSTAR) !== -1; + return pattern.includes(GLOBSTAR); } exports.hasGlobStar = hasGlobStar; function endsWithSlashGlobStar(pattern) { @@ -70151,7 +70186,7 @@ function convertPatternsToRe(patterns, options) { } exports.convertPatternsToRe = convertPatternsToRe; function matchAny(entry, patternsRe) { - const filepath = entry.replace(/^\.[\\\/]/, ''); + const filepath = entry.replace(/^\.[\\/]/, ''); return patternsRe.some((patternRe) => patternRe.test(filepath)); } exports.matchAny = matchAny; @@ -70174,9 +70209,16 @@ var enclosure = /[\{\[].*[\/]*.*[\}\]]$/; var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/; var escaped = /\\([\*\?\|\[\]\(\)\{\}])/g; -module.exports = function globParent(str) { +/** + * @param {string} str + * @param {Object} opts + * @param {boolean} [opts.flipBackslashes=true] + */ +module.exports = function globParent(str, opts) { + var options = Object.assign({ flipBackslashes: true }, opts); + // flip windows path separators - if (isWin32 && str.indexOf(slash) < 0) { + if (options.flipBackslashes && isWin32 && str.indexOf(slash) < 0) { str = str.replace(backslash, slash); } @@ -74070,26 +74112,145 @@ module.exports = parse; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const merge2 = __webpack_require__(590); +const merge2 = __webpack_require__(625); function merge(streams) { const mergedStream = merge2(streams); streams.forEach((stream) => { - stream.once('error', (err) => mergedStream.emit('error', err)); + stream.once('error', (error) => mergedStream.emit('error', error)); }); + mergedStream.once('close', () => propagateCloseEventToSources(streams)); + mergedStream.once('end', () => propagateCloseEventToSources(streams)); return mergedStream; } exports.merge = merge; +function propagateCloseEventToSources(streams) { + streams.forEach((stream) => stream.emit('close')); +} /***/ }), /* 625 */ /***/ (function(module, exports, __webpack_require__) { +"use strict"; + +/* + * merge2 + * https://github.com/teambition/merge2 + * + * Copyright (c) 2014-2016 Teambition + * Licensed under the MIT license. + */ +const Stream = __webpack_require__(27) +const PassThrough = Stream.PassThrough +const slice = Array.prototype.slice + +module.exports = merge2 + +function merge2 () { + const streamsQueue = [] + let merging = false + const args = slice.call(arguments) + let options = args[args.length - 1] + + if (options && !Array.isArray(options) && options.pipe == null) args.pop() + else options = {} + + const doEnd = options.end !== false + if (options.objectMode == null) options.objectMode = true + if (options.highWaterMark == null) options.highWaterMark = 64 * 1024 + const mergedStream = PassThrough(options) + + function addStream () { + for (let i = 0, len = arguments.length; i < len; i++) { + streamsQueue.push(pauseStreams(arguments[i], options)) + } + mergeStream() + return this + } + + function mergeStream () { + if (merging) return + merging = true + + let streams = streamsQueue.shift() + if (!streams) { + process.nextTick(endStream) + return + } + if (!Array.isArray(streams)) streams = [streams] + + let pipesCount = streams.length + 1 + + function next () { + if (--pipesCount > 0) return + merging = false + mergeStream() + } + + function pipe (stream) { + function onend () { + stream.removeListener('merge2UnpipeEnd', onend) + stream.removeListener('end', onend) + next() + } + // skip ended stream + if (stream._readableState.endEmitted) return next() + + stream.on('merge2UnpipeEnd', onend) + stream.on('end', onend) + stream.pipe(mergedStream, { end: false }) + // compatible for old stream + stream.resume() + } + + for (let i = 0; i < streams.length; i++) pipe(streams[i]) + + next() + } + + function endStream () { + merging = false + // emit 'queueDrain' when all streams merged. + mergedStream.emit('queueDrain') + return doEnd && mergedStream.end() + } + + mergedStream.setMaxListeners(0) + mergedStream.add = addStream + mergedStream.on('unpipe', function (stream) { + stream.emit('merge2UnpipeEnd') + }) + + if (args.length) addStream.apply(null, args) + return mergedStream +} + +// check and pause streams for pipe. +function pauseStreams (streams, options) { + if (!Array.isArray(streams)) { + // Backwards-compat with old-style streams + if (!streams._readableState && streams.pipe) streams = streams.pipe(PassThrough(options)) + if (!streams._readableState || !streams.pause || !streams.pipe) { + throw new Error('Only readable stream can be merged.') + } + streams.pause() + } else { + for (let i = 0, len = streams.length; i < len; i++) streams[i] = pauseStreams(streams[i], options) + } + return streams +} + + +/***/ }), +/* 626 */ +/***/ (function(module, exports, __webpack_require__) { + "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(626); -const provider_1 = __webpack_require__(653); +const stream_1 = __webpack_require__(627); +const provider_1 = __webpack_require__(654); class ProviderAsync extends provider_1.default { constructor() { super(...arguments); @@ -74117,16 +74278,16 @@ exports.default = ProviderAsync; /***/ }), -/* 626 */ +/* 627 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(27); -const fsStat = __webpack_require__(627); -const fsWalk = __webpack_require__(632); -const reader_1 = __webpack_require__(652); +const fsStat = __webpack_require__(628); +const fsWalk = __webpack_require__(633); +const reader_1 = __webpack_require__(653); class ReaderStream extends reader_1.default { constructor() { super(...arguments); @@ -74170,7 +74331,7 @@ class ReaderStream extends reader_1.default { _getStat(filepath) { return new Promise((resolve, reject) => { this._stat(filepath, this._fsStatSettings, (error, stats) => { - error ? reject(error) : resolve(stats); + return error === null ? resolve(stats) : reject(error); }); }); } @@ -74179,15 +74340,15 @@ exports.default = ReaderStream; /***/ }), -/* 627 */ +/* 628 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async = __webpack_require__(628); -const sync = __webpack_require__(629); -const settings_1 = __webpack_require__(630); +const async = __webpack_require__(629); +const sync = __webpack_require__(630); +const settings_1 = __webpack_require__(631); exports.Settings = settings_1.default; function stat(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -74210,7 +74371,7 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 628 */ +/* 629 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74218,14 +74379,14 @@ function getSettings(settingsOrOptions = {}) { Object.defineProperty(exports, "__esModule", { value: true }); function read(path, settings, callback) { settings.fs.lstat(path, (lstatError, lstat) => { - if (lstatError) { + if (lstatError !== null) { return callFailureCallback(callback, lstatError); } if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) { return callSuccessCallback(callback, lstat); } settings.fs.stat(path, (statError, stat) => { - if (statError) { + if (statError !== null) { if (settings.throwErrorOnBrokenSymbolicLink) { return callFailureCallback(callback, statError); } @@ -74248,7 +74409,7 @@ function callSuccessCallback(callback, result) { /***/ }), -/* 629 */ +/* 630 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74277,13 +74438,13 @@ exports.read = read; /***/ }), -/* 630 */ +/* 631 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(631); +const fs = __webpack_require__(632); class Settings { constructor(_options = {}) { this._options = _options; @@ -74300,7 +74461,7 @@ exports.default = Settings; /***/ }), -/* 631 */ +/* 632 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74314,42 +74475,42 @@ exports.FILE_SYSTEM_ADAPTER = { statSync: fs.statSync }; function createFileSystemAdapter(fsMethods) { - if (!fsMethods) { + if (fsMethods === undefined) { return exports.FILE_SYSTEM_ADAPTER; } - return Object.assign({}, exports.FILE_SYSTEM_ADAPTER, fsMethods); + return Object.assign(Object.assign({}, exports.FILE_SYSTEM_ADAPTER), fsMethods); } exports.createFileSystemAdapter = createFileSystemAdapter; /***/ }), -/* 632 */ +/* 633 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(633); -const stream_1 = __webpack_require__(648); -const sync_1 = __webpack_require__(649); -const settings_1 = __webpack_require__(651); +const async_1 = __webpack_require__(634); +const stream_1 = __webpack_require__(649); +const sync_1 = __webpack_require__(650); +const settings_1 = __webpack_require__(652); exports.Settings = settings_1.default; -function walk(dir, optionsOrSettingsOrCallback, callback) { +function walk(directory, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { - return new async_1.default(dir, getSettings()).read(optionsOrSettingsOrCallback); + return new async_1.default(directory, getSettings()).read(optionsOrSettingsOrCallback); } - new async_1.default(dir, getSettings(optionsOrSettingsOrCallback)).read(callback); + new async_1.default(directory, getSettings(optionsOrSettingsOrCallback)).read(callback); } exports.walk = walk; -function walkSync(dir, optionsOrSettings) { +function walkSync(directory, optionsOrSettings) { const settings = getSettings(optionsOrSettings); - const provider = new sync_1.default(dir, settings); + const provider = new sync_1.default(directory, settings); return provider.read(); } exports.walkSync = walkSync; -function walkStream(dir, optionsOrSettings) { +function walkStream(directory, optionsOrSettings) { const settings = getSettings(optionsOrSettings); - const provider = new stream_1.default(dir, settings); + const provider = new stream_1.default(directory, settings); return provider.read(); } exports.walkStream = walkStream; @@ -74362,13 +74523,13 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 633 */ +/* 634 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(634); +const async_1 = __webpack_require__(635); class AsyncProvider { constructor(_root, _settings) { this._root = _root; @@ -74384,7 +74545,7 @@ class AsyncProvider { this._storage.add(entry); }); this._reader.onEnd(() => { - callSuccessCallback(callback, Array.from(this._storage)); + callSuccessCallback(callback, [...this._storage]); }); this._reader.read(); } @@ -74399,17 +74560,17 @@ function callSuccessCallback(callback, entries) { /***/ }), -/* 634 */ +/* 635 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = __webpack_require__(379); -const fsScandir = __webpack_require__(635); -const fastq = __webpack_require__(644); -const common = __webpack_require__(646); -const reader_1 = __webpack_require__(647); +const fsScandir = __webpack_require__(636); +const fastq = __webpack_require__(645); +const common = __webpack_require__(647); +const reader_1 = __webpack_require__(648); class AsyncReader extends reader_1.default { constructor(_root, _settings) { super(_root, _settings); @@ -74449,17 +74610,17 @@ class AsyncReader extends reader_1.default { onEnd(callback) { this._emitter.once('end', callback); } - _pushToQueue(dir, base) { - const queueItem = { dir, base }; + _pushToQueue(directory, base) { + const queueItem = { directory, base }; this._queue.push(queueItem, (error) => { - if (error) { + if (error !== null) { this._handleError(error); } }); } _worker(item, done) { - this._scandir(item.dir, this._settings.fsScandirSettings, (error, entries) => { - if (error) { + this._scandir(item.directory, this._settings.fsScandirSettings, (error, entries) => { + if (error !== null) { return done(error, undefined); } for (const entry of entries) { @@ -74499,15 +74660,15 @@ exports.default = AsyncReader; /***/ }), -/* 635 */ +/* 636 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async = __webpack_require__(636); -const sync = __webpack_require__(641); -const settings_1 = __webpack_require__(642); +const async = __webpack_require__(637); +const sync = __webpack_require__(642); +const settings_1 = __webpack_require__(643); exports.Settings = settings_1.default; function scandir(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -74530,39 +74691,39 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 636 */ +/* 637 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(627); -const rpl = __webpack_require__(637); -const constants_1 = __webpack_require__(638); -const utils = __webpack_require__(639); -function read(dir, settings, callback) { +const fsStat = __webpack_require__(628); +const rpl = __webpack_require__(638); +const constants_1 = __webpack_require__(639); +const utils = __webpack_require__(640); +function read(directory, settings, callback) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { - return readdirWithFileTypes(dir, settings, callback); + return readdirWithFileTypes(directory, settings, callback); } - return readdir(dir, settings, callback); + return readdir(directory, settings, callback); } exports.read = read; -function readdirWithFileTypes(dir, settings, callback) { - settings.fs.readdir(dir, { withFileTypes: true }, (readdirError, dirents) => { - if (readdirError) { +function readdirWithFileTypes(directory, settings, callback) { + settings.fs.readdir(directory, { withFileTypes: true }, (readdirError, dirents) => { + if (readdirError !== null) { return callFailureCallback(callback, readdirError); } const entries = dirents.map((dirent) => ({ dirent, name: dirent.name, - path: `${dir}${settings.pathSegmentSeparator}${dirent.name}` + path: `${directory}${settings.pathSegmentSeparator}${dirent.name}` })); if (!settings.followSymbolicLinks) { return callSuccessCallback(callback, entries); } const tasks = entries.map((entry) => makeRplTaskEntry(entry, settings)); rpl(tasks, (rplError, rplEntries) => { - if (rplError) { + if (rplError !== null) { return callFailureCallback(callback, rplError); } callSuccessCallback(callback, rplEntries); @@ -74576,7 +74737,7 @@ function makeRplTaskEntry(entry, settings) { return done(null, entry); } settings.fs.stat(entry.path, (statError, stats) => { - if (statError) { + if (statError !== null) { if (settings.throwErrorOnBrokenSymbolicLink) { return done(statError); } @@ -74587,22 +74748,21 @@ function makeRplTaskEntry(entry, settings) { }); }; } -function readdir(dir, settings, callback) { - settings.fs.readdir(dir, (readdirError, names) => { - if (readdirError) { +function readdir(directory, settings, callback) { + settings.fs.readdir(directory, (readdirError, names) => { + if (readdirError !== null) { return callFailureCallback(callback, readdirError); } - const filepaths = names.map((name) => `${dir}${settings.pathSegmentSeparator}${name}`); + const filepaths = names.map((name) => `${directory}${settings.pathSegmentSeparator}${name}`); const tasks = filepaths.map((filepath) => { return (done) => fsStat.stat(filepath, settings.fsStatSettings, done); }); rpl(tasks, (rplError, results) => { - if (rplError) { + if (rplError !== null) { return callFailureCallback(callback, rplError); } const entries = []; - for (let index = 0; index < names.length; index++) { - const name = names[index]; + names.forEach((name, index) => { const stats = results[index]; const entry = { name, @@ -74613,7 +74773,7 @@ function readdir(dir, settings, callback) { entry.stats = stats; } entries.push(entry); - } + }); callSuccessCallback(callback, entries); }); }); @@ -74628,7 +74788,7 @@ function callSuccessCallback(callback, result) { /***/ }), -/* 637 */ +/* 638 */ /***/ (function(module, exports) { module.exports = runParallel @@ -74682,7 +74842,7 @@ function runParallel (tasks, cb) { /***/ }), -/* 638 */ +/* 639 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74691,25 +74851,29 @@ Object.defineProperty(exports, "__esModule", { value: true }); const NODE_PROCESS_VERSION_PARTS = process.versions.node.split('.'); const MAJOR_VERSION = parseInt(NODE_PROCESS_VERSION_PARTS[0], 10); const MINOR_VERSION = parseInt(NODE_PROCESS_VERSION_PARTS[1], 10); +const SUPPORTED_MAJOR_VERSION = 10; +const SUPPORTED_MINOR_VERSION = 10; +const IS_MATCHED_BY_MAJOR = MAJOR_VERSION > SUPPORTED_MAJOR_VERSION; +const IS_MATCHED_BY_MAJOR_AND_MINOR = MAJOR_VERSION === SUPPORTED_MAJOR_VERSION && MINOR_VERSION >= SUPPORTED_MINOR_VERSION; /** * IS `true` for Node.js 10.10 and greater. */ -exports.IS_SUPPORT_READDIR_WITH_FILE_TYPES = MAJOR_VERSION > 10 || (MAJOR_VERSION === 10 && MINOR_VERSION >= 10); +exports.IS_SUPPORT_READDIR_WITH_FILE_TYPES = IS_MATCHED_BY_MAJOR || IS_MATCHED_BY_MAJOR_AND_MINOR; /***/ }), -/* 639 */ +/* 640 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(640); +const fs = __webpack_require__(641); exports.fs = fs; /***/ }), -/* 640 */ +/* 641 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74734,29 +74898,29 @@ exports.createDirentFromStats = createDirentFromStats; /***/ }), -/* 641 */ +/* 642 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(627); -const constants_1 = __webpack_require__(638); -const utils = __webpack_require__(639); -function read(dir, settings) { +const fsStat = __webpack_require__(628); +const constants_1 = __webpack_require__(639); +const utils = __webpack_require__(640); +function read(directory, settings) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { - return readdirWithFileTypes(dir, settings); + return readdirWithFileTypes(directory, settings); } - return readdir(dir, settings); + return readdir(directory, settings); } exports.read = read; -function readdirWithFileTypes(dir, settings) { - const dirents = settings.fs.readdirSync(dir, { withFileTypes: true }); +function readdirWithFileTypes(directory, settings) { + const dirents = settings.fs.readdirSync(directory, { withFileTypes: true }); return dirents.map((dirent) => { const entry = { dirent, name: dirent.name, - path: `${dir}${settings.pathSegmentSeparator}${dirent.name}` + path: `${directory}${settings.pathSegmentSeparator}${dirent.name}` }; if (entry.dirent.isSymbolicLink() && settings.followSymbolicLinks) { try { @@ -74773,10 +74937,10 @@ function readdirWithFileTypes(dir, settings) { }); } exports.readdirWithFileTypes = readdirWithFileTypes; -function readdir(dir, settings) { - const names = settings.fs.readdirSync(dir); +function readdir(directory, settings) { + const names = settings.fs.readdirSync(directory); return names.map((name) => { - const entryPath = `${dir}${settings.pathSegmentSeparator}${name}`; + const entryPath = `${directory}${settings.pathSegmentSeparator}${name}`; const stats = fsStat.statSync(entryPath, settings.fsStatSettings); const entry = { name, @@ -74793,15 +74957,15 @@ exports.readdir = readdir; /***/ }), -/* 642 */ +/* 643 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const fsStat = __webpack_require__(627); -const fs = __webpack_require__(643); +const fsStat = __webpack_require__(628); +const fs = __webpack_require__(644); class Settings { constructor(_options = {}) { this._options = _options; @@ -74824,7 +74988,7 @@ exports.default = Settings; /***/ }), -/* 643 */ +/* 644 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74840,22 +75004,22 @@ exports.FILE_SYSTEM_ADAPTER = { readdirSync: fs.readdirSync }; function createFileSystemAdapter(fsMethods) { - if (!fsMethods) { + if (fsMethods === undefined) { return exports.FILE_SYSTEM_ADAPTER; } - return Object.assign({}, exports.FILE_SYSTEM_ADAPTER, fsMethods); + return Object.assign(Object.assign({}, exports.FILE_SYSTEM_ADAPTER), fsMethods); } exports.createFileSystemAdapter = createFileSystemAdapter; /***/ }), -/* 644 */ +/* 645 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var reusify = __webpack_require__(645) +var reusify = __webpack_require__(646) function fastqueue (context, worker, concurrency) { if (typeof context === 'function') { @@ -75029,7 +75193,7 @@ module.exports = fastqueue /***/ }), -/* 645 */ +/* 646 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75069,7 +75233,7 @@ module.exports = reusify /***/ }), -/* 646 */ +/* 647 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75087,7 +75251,7 @@ function isAppliedFilter(filter, value) { } exports.isAppliedFilter = isAppliedFilter; function replacePathSegmentSeparator(filepath, separator) { - return filepath.split(/[\\\/]/).join(separator); + return filepath.split(/[\\/]/).join(separator); } exports.replacePathSegmentSeparator = replacePathSegmentSeparator; function joinPathSegments(a, b, separator) { @@ -75100,13 +75264,13 @@ exports.joinPathSegments = joinPathSegments; /***/ }), -/* 647 */ +/* 648 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const common = __webpack_require__(646); +const common = __webpack_require__(647); class Reader { constructor(_root, _settings) { this._root = _root; @@ -75118,14 +75282,14 @@ exports.default = Reader; /***/ }), -/* 648 */ +/* 649 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(27); -const async_1 = __webpack_require__(634); +const async_1 = __webpack_require__(635); class StreamProvider { constructor(_root, _settings) { this._root = _root; @@ -75155,13 +75319,13 @@ exports.default = StreamProvider; /***/ }), -/* 649 */ +/* 650 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(650); +const sync_1 = __webpack_require__(651); class SyncProvider { constructor(_root, _settings) { this._root = _root; @@ -75176,15 +75340,15 @@ exports.default = SyncProvider; /***/ }), -/* 650 */ +/* 651 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsScandir = __webpack_require__(635); -const common = __webpack_require__(646); -const reader_1 = __webpack_require__(647); +const fsScandir = __webpack_require__(636); +const common = __webpack_require__(647); +const reader_1 = __webpack_require__(648); class SyncReader extends reader_1.default { constructor() { super(...arguments); @@ -75195,19 +75359,19 @@ class SyncReader extends reader_1.default { read() { this._pushToQueue(this._root, this._settings.basePath); this._handleQueue(); - return Array.from(this._storage); + return [...this._storage]; } - _pushToQueue(dir, base) { - this._queue.add({ dir, base }); + _pushToQueue(directory, base) { + this._queue.add({ directory, base }); } _handleQueue() { for (const item of this._queue.values()) { - this._handleDirectory(item.dir, item.base); + this._handleDirectory(item.directory, item.base); } } - _handleDirectory(dir, base) { + _handleDirectory(directory, base) { try { - const entries = this._scandir(dir, this._settings.fsScandirSettings); + const entries = this._scandir(directory, this._settings.fsScandirSettings); for (const entry of entries) { this._handleEntry(entry, base); } @@ -75242,14 +75406,14 @@ exports.default = SyncReader; /***/ }), -/* 651 */ +/* 652 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const fsScandir = __webpack_require__(635); +const fsScandir = __webpack_require__(636); class Settings { constructor(_options = {}) { this._options = _options; @@ -75275,14 +75439,14 @@ exports.default = Settings; /***/ }), -/* 652 */ +/* 653 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const fsStat = __webpack_require__(627); +const fsStat = __webpack_require__(628); const utils = __webpack_require__(598); class Reader { constructor(_settings) { @@ -75315,17 +75479,17 @@ exports.default = Reader; /***/ }), -/* 653 */ +/* 654 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const deep_1 = __webpack_require__(654); -const entry_1 = __webpack_require__(655); -const error_1 = __webpack_require__(656); -const entry_2 = __webpack_require__(657); +const deep_1 = __webpack_require__(655); +const entry_1 = __webpack_require__(656); +const error_1 = __webpack_require__(657); +const entry_2 = __webpack_require__(658); class Provider { constructor(_settings) { this._settings = _settings; @@ -75370,7 +75534,7 @@ exports.default = Provider; /***/ }), -/* 654 */ +/* 655 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75406,9 +75570,6 @@ class DeepFilter { if (this._isSkippedSymbolicLink(entry)) { return false; } - if (this._isSkippedDotDirectory(entry)) { - return false; - } return this._isSkippedByNegativePatterns(entry, negativeRe); } _getEntryDepth(basePath, entryPath) { @@ -75425,9 +75586,6 @@ class DeepFilter { _isSkippedSymbolicLink(entry) { return !this._settings.followSymbolicLinks && entry.dirent.isSymbolicLink(); } - _isSkippedDotDirectory(entry) { - return !this._settings.dot && entry.name.startsWith('.'); - } _isSkippedByNegativePatterns(entry, negativeRe) { return !utils.pattern.matchAny(entry.path, negativeRe); } @@ -75436,7 +75594,7 @@ exports.default = DeepFilter; /***/ }), -/* 655 */ +/* 656 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75497,7 +75655,7 @@ exports.default = EntryFilter; /***/ }), -/* 656 */ +/* 657 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75519,7 +75677,7 @@ exports.default = ErrorFilter; /***/ }), -/* 657 */ +/* 658 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75545,22 +75703,22 @@ class EntryTransformer { if (!this._settings.objectMode) { return filepath; } - return Object.assign({}, entry, { path: filepath }); + return Object.assign(Object.assign({}, entry), { path: filepath }); } } exports.default = EntryTransformer; /***/ }), -/* 658 */ +/* 659 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(27); -const stream_2 = __webpack_require__(626); -const provider_1 = __webpack_require__(653); +const stream_2 = __webpack_require__(627); +const provider_1 = __webpack_require__(654); class ProviderStream extends provider_1.default { constructor() { super(...arguments); @@ -75570,12 +75728,14 @@ class ProviderStream extends provider_1.default { const root = this._getRootDirectory(task); const options = this._getReaderOptions(task); const source = this.api(root, task, options); - const dest = new stream_1.Readable({ objectMode: true, read: () => { } }); + const destination = new stream_1.Readable({ objectMode: true, read: () => { } }); source - .once('error', (error) => dest.emit('error', error)) - .on('data', (entry) => dest.emit('data', options.transform(entry))) - .once('end', () => dest.emit('end')); - return dest; + .once('error', (error) => destination.emit('error', error)) + .on('data', (entry) => destination.emit('data', options.transform(entry))) + .once('end', () => destination.emit('end')); + destination + .once('close', () => source.destroy()); + return destination; } api(root, task, options) { if (task.dynamic) { @@ -75588,14 +75748,14 @@ exports.default = ProviderStream; /***/ }), -/* 659 */ +/* 660 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(660); -const provider_1 = __webpack_require__(653); +const sync_1 = __webpack_require__(661); +const provider_1 = __webpack_require__(654); class ProviderSync extends provider_1.default { constructor() { super(...arguments); @@ -75618,15 +75778,15 @@ exports.default = ProviderSync; /***/ }), -/* 660 */ +/* 661 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(627); -const fsWalk = __webpack_require__(632); -const reader_1 = __webpack_require__(652); +const fsStat = __webpack_require__(628); +const fsWalk = __webpack_require__(633); +const reader_1 = __webpack_require__(653); class ReaderSync extends reader_1.default { constructor() { super(...arguments); @@ -75668,7 +75828,7 @@ exports.default = ReaderSync; /***/ }), -/* 661 */ +/* 662 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75685,7 +75845,6 @@ exports.DEFAULT_FILE_SYSTEM_ADAPTER = { readdir: fs.readdir, readdirSync: fs.readdirSync }; -// tslint:enable no-redundant-jsdoc class Settings { constructor(_options = {}) { this._options = _options; @@ -75721,20 +75880,20 @@ class Settings { return option === undefined ? value : option; } _getFileSystemMethods(methods = {}) { - return Object.assign({}, exports.DEFAULT_FILE_SYSTEM_ADAPTER, methods); + return Object.assign(Object.assign({}, exports.DEFAULT_FILE_SYSTEM_ADAPTER), methods); } } exports.default = Settings; /***/ }), -/* 662 */ +/* 663 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const pathType = __webpack_require__(663); +const pathType = __webpack_require__(664); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -75810,7 +75969,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 663 */ +/* 664 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75860,7 +76019,7 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 664 */ +/* 665 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75869,8 +76028,8 @@ const {promisify} = __webpack_require__(29); const fs = __webpack_require__(23); const path = __webpack_require__(16); const fastGlob = __webpack_require__(596); -const gitIgnore = __webpack_require__(665); -const slash = __webpack_require__(666); +const gitIgnore = __webpack_require__(666); +const slash = __webpack_require__(667); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -75984,7 +76143,7 @@ module.exports.sync = options => { /***/ }), -/* 665 */ +/* 666 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -76575,7 +76734,7 @@ if ( /***/ }), -/* 666 */ +/* 667 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76593,7 +76752,7 @@ module.exports = path => { /***/ }), -/* 667 */ +/* 668 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76646,7 +76805,7 @@ module.exports = { /***/ }), -/* 668 */ +/* 669 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76668,7 +76827,7 @@ module.exports = path_ => { /***/ }), -/* 669 */ +/* 670 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76696,7 +76855,7 @@ module.exports = (childPath, parentPath) => { /***/ }), -/* 670 */ +/* 671 */ /***/ (function(module, exports, __webpack_require__) { const assert = __webpack_require__(30) @@ -77070,12 +77229,12 @@ rimraf.sync = rimrafSync /***/ }), -/* 671 */ +/* 672 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const AggregateError = __webpack_require__(672); +const AggregateError = __webpack_require__(673); module.exports = async ( iterable, @@ -77158,13 +77317,13 @@ module.exports = async ( /***/ }), -/* 672 */ +/* 673 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const indentString = __webpack_require__(673); -const cleanStack = __webpack_require__(674); +const indentString = __webpack_require__(674); +const cleanStack = __webpack_require__(675); const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); @@ -77212,7 +77371,7 @@ module.exports = AggregateError; /***/ }), -/* 673 */ +/* 674 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77254,7 +77413,7 @@ module.exports = (string, count = 1, options) => { /***/ }), -/* 674 */ +/* 675 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77301,14 +77460,14 @@ module.exports = (stack, options) => { /***/ }), -/* 675 */ +/* 676 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const chalk = __webpack_require__(676); -const cliCursor = __webpack_require__(680); -const cliSpinners = __webpack_require__(684); +const chalk = __webpack_require__(677); +const cliCursor = __webpack_require__(681); +const cliSpinners = __webpack_require__(685); const logSymbols = __webpack_require__(565); class Ora { @@ -77456,16 +77615,16 @@ module.exports.promise = (action, options) => { /***/ }), -/* 676 */ +/* 677 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const escapeStringRegexp = __webpack_require__(3); -const ansiStyles = __webpack_require__(677); -const stdoutColor = __webpack_require__(678).stdout; +const ansiStyles = __webpack_require__(678); +const stdoutColor = __webpack_require__(679).stdout; -const template = __webpack_require__(679); +const template = __webpack_require__(680); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -77691,7 +77850,7 @@ module.exports.default = module.exports; // For TypeScript /***/ }), -/* 677 */ +/* 678 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77864,7 +78023,7 @@ Object.defineProperty(module, 'exports', { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 678 */ +/* 679 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78006,7 +78165,7 @@ module.exports = { /***/ }), -/* 679 */ +/* 680 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78141,12 +78300,12 @@ module.exports = (chalk, tmp) => { /***/ }), -/* 680 */ +/* 681 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const restoreCursor = __webpack_require__(681); +const restoreCursor = __webpack_require__(682); let hidden = false; @@ -78187,12 +78346,12 @@ exports.toggle = (force, stream) => { /***/ }), -/* 681 */ +/* 682 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const onetime = __webpack_require__(682); +const onetime = __webpack_require__(683); const signalExit = __webpack_require__(377); module.exports = onetime(() => { @@ -78203,12 +78362,12 @@ module.exports = onetime(() => { /***/ }), -/* 682 */ +/* 683 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const mimicFn = __webpack_require__(683); +const mimicFn = __webpack_require__(684); module.exports = (fn, opts) => { // TODO: Remove this in v3 @@ -78249,7 +78408,7 @@ module.exports = (fn, opts) => { /***/ }), -/* 683 */ +/* 684 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78265,22 +78424,22 @@ module.exports = (to, from) => { /***/ }), -/* 684 */ +/* 685 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = __webpack_require__(685); +module.exports = __webpack_require__(686); /***/ }), -/* 685 */ +/* 686 */ /***/ (function(module) { module.exports = JSON.parse("{\"dots\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠹\",\"⠸\",\"⠼\",\"⠴\",\"⠦\",\"⠧\",\"⠇\",\"⠏\"]},\"dots2\":{\"interval\":80,\"frames\":[\"⣾\",\"⣽\",\"⣻\",\"⢿\",\"⡿\",\"⣟\",\"⣯\",\"⣷\"]},\"dots3\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠞\",\"⠖\",\"⠦\",\"⠴\",\"⠲\",\"⠳\",\"⠓\"]},\"dots4\":{\"interval\":80,\"frames\":[\"⠄\",\"⠆\",\"⠇\",\"⠋\",\"⠙\",\"⠸\",\"⠰\",\"⠠\",\"⠰\",\"⠸\",\"⠙\",\"⠋\",\"⠇\",\"⠆\"]},\"dots5\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\"]},\"dots6\":{\"interval\":80,\"frames\":[\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠴\",\"⠲\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠚\",\"⠙\",\"⠉\",\"⠁\"]},\"dots7\":{\"interval\":80,\"frames\":[\"⠈\",\"⠉\",\"⠋\",\"⠓\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠖\",\"⠦\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\"]},\"dots8\":{\"interval\":80,\"frames\":[\"⠁\",\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\",\"⠈\"]},\"dots9\":{\"interval\":80,\"frames\":[\"⢹\",\"⢺\",\"⢼\",\"⣸\",\"⣇\",\"⡧\",\"⡗\",\"⡏\"]},\"dots10\":{\"interval\":80,\"frames\":[\"⢄\",\"⢂\",\"⢁\",\"⡁\",\"⡈\",\"⡐\",\"⡠\"]},\"dots11\":{\"interval\":100,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⡀\",\"⢀\",\"⠠\",\"⠐\",\"⠈\"]},\"dots12\":{\"interval\":80,\"frames\":[\"⢀⠀\",\"⡀⠀\",\"⠄⠀\",\"⢂⠀\",\"⡂⠀\",\"⠅⠀\",\"⢃⠀\",\"⡃⠀\",\"⠍⠀\",\"⢋⠀\",\"⡋⠀\",\"⠍⠁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⢈⠩\",\"⡀⢙\",\"⠄⡙\",\"⢂⠩\",\"⡂⢘\",\"⠅⡘\",\"⢃⠨\",\"⡃⢐\",\"⠍⡐\",\"⢋⠠\",\"⡋⢀\",\"⠍⡁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⠈⠩\",\"⠀⢙\",\"⠀⡙\",\"⠀⠩\",\"⠀⢘\",\"⠀⡘\",\"⠀⠨\",\"⠀⢐\",\"⠀⡐\",\"⠀⠠\",\"⠀⢀\",\"⠀⡀\"]},\"line\":{\"interval\":130,\"frames\":[\"-\",\"\\\\\",\"|\",\"/\"]},\"line2\":{\"interval\":100,\"frames\":[\"⠂\",\"-\",\"–\",\"—\",\"–\",\"-\"]},\"pipe\":{\"interval\":100,\"frames\":[\"┤\",\"┘\",\"┴\",\"└\",\"├\",\"┌\",\"┬\",\"┐\"]},\"simpleDots\":{\"interval\":400,\"frames\":[\". \",\".. \",\"...\",\" \"]},\"simpleDotsScrolling\":{\"interval\":200,\"frames\":[\". \",\".. \",\"...\",\" ..\",\" .\",\" \"]},\"star\":{\"interval\":70,\"frames\":[\"✶\",\"✸\",\"✹\",\"✺\",\"✹\",\"✷\"]},\"star2\":{\"interval\":80,\"frames\":[\"+\",\"x\",\"*\"]},\"flip\":{\"interval\":70,\"frames\":[\"_\",\"_\",\"_\",\"-\",\"`\",\"`\",\"'\",\"´\",\"-\",\"_\",\"_\",\"_\"]},\"hamburger\":{\"interval\":100,\"frames\":[\"☱\",\"☲\",\"☴\"]},\"growVertical\":{\"interval\":120,\"frames\":[\"▁\",\"▃\",\"▄\",\"▅\",\"▆\",\"▇\",\"▆\",\"▅\",\"▄\",\"▃\"]},\"growHorizontal\":{\"interval\":120,\"frames\":[\"▏\",\"▎\",\"▍\",\"▌\",\"▋\",\"▊\",\"▉\",\"▊\",\"▋\",\"▌\",\"▍\",\"▎\"]},\"balloon\":{\"interval\":140,\"frames\":[\" \",\".\",\"o\",\"O\",\"@\",\"*\",\" \"]},\"balloon2\":{\"interval\":120,\"frames\":[\".\",\"o\",\"O\",\"°\",\"O\",\"o\",\".\"]},\"noise\":{\"interval\":100,\"frames\":[\"▓\",\"▒\",\"░\"]},\"bounce\":{\"interval\":120,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⠂\"]},\"boxBounce\":{\"interval\":120,\"frames\":[\"▖\",\"▘\",\"▝\",\"▗\"]},\"boxBounce2\":{\"interval\":100,\"frames\":[\"▌\",\"▀\",\"▐\",\"▄\"]},\"triangle\":{\"interval\":50,\"frames\":[\"◢\",\"◣\",\"◤\",\"◥\"]},\"arc\":{\"interval\":100,\"frames\":[\"◜\",\"◠\",\"◝\",\"◞\",\"◡\",\"◟\"]},\"circle\":{\"interval\":120,\"frames\":[\"◡\",\"⊙\",\"◠\"]},\"squareCorners\":{\"interval\":180,\"frames\":[\"◰\",\"◳\",\"◲\",\"◱\"]},\"circleQuarters\":{\"interval\":120,\"frames\":[\"◴\",\"◷\",\"◶\",\"◵\"]},\"circleHalves\":{\"interval\":50,\"frames\":[\"◐\",\"◓\",\"◑\",\"◒\"]},\"squish\":{\"interval\":100,\"frames\":[\"╫\",\"╪\"]},\"toggle\":{\"interval\":250,\"frames\":[\"⊶\",\"⊷\"]},\"toggle2\":{\"interval\":80,\"frames\":[\"▫\",\"▪\"]},\"toggle3\":{\"interval\":120,\"frames\":[\"□\",\"■\"]},\"toggle4\":{\"interval\":100,\"frames\":[\"■\",\"□\",\"▪\",\"▫\"]},\"toggle5\":{\"interval\":100,\"frames\":[\"▮\",\"▯\"]},\"toggle6\":{\"interval\":300,\"frames\":[\"ဝ\",\"၀\"]},\"toggle7\":{\"interval\":80,\"frames\":[\"⦾\",\"⦿\"]},\"toggle8\":{\"interval\":100,\"frames\":[\"◍\",\"◌\"]},\"toggle9\":{\"interval\":100,\"frames\":[\"◉\",\"◎\"]},\"toggle10\":{\"interval\":100,\"frames\":[\"㊂\",\"㊀\",\"㊁\"]},\"toggle11\":{\"interval\":50,\"frames\":[\"⧇\",\"⧆\"]},\"toggle12\":{\"interval\":120,\"frames\":[\"☗\",\"☖\"]},\"toggle13\":{\"interval\":80,\"frames\":[\"=\",\"*\",\"-\"]},\"arrow\":{\"interval\":100,\"frames\":[\"←\",\"↖\",\"↑\",\"↗\",\"→\",\"↘\",\"↓\",\"↙\"]},\"arrow2\":{\"interval\":80,\"frames\":[\"⬆️ \",\"↗️ \",\"➡️ \",\"↘️ \",\"⬇️ \",\"↙️ \",\"⬅️ \",\"↖️ \"]},\"arrow3\":{\"interval\":120,\"frames\":[\"▹▹▹▹▹\",\"▸▹▹▹▹\",\"▹▸▹▹▹\",\"▹▹▸▹▹\",\"▹▹▹▸▹\",\"▹▹▹▹▸\"]},\"bouncingBar\":{\"interval\":80,\"frames\":[\"[ ]\",\"[= ]\",\"[== ]\",\"[=== ]\",\"[ ===]\",\"[ ==]\",\"[ =]\",\"[ ]\",\"[ =]\",\"[ ==]\",\"[ ===]\",\"[====]\",\"[=== ]\",\"[== ]\",\"[= ]\"]},\"bouncingBall\":{\"interval\":80,\"frames\":[\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ●)\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"(● )\"]},\"smiley\":{\"interval\":200,\"frames\":[\"😄 \",\"😝 \"]},\"monkey\":{\"interval\":300,\"frames\":[\"🙈 \",\"🙈 \",\"🙉 \",\"🙊 \"]},\"hearts\":{\"interval\":100,\"frames\":[\"💛 \",\"💙 \",\"💜 \",\"💚 \",\"❤️ \"]},\"clock\":{\"interval\":100,\"frames\":[\"🕐 \",\"🕑 \",\"🕒 \",\"🕓 \",\"🕔 \",\"🕕 \",\"🕖 \",\"🕗 \",\"🕘 \",\"🕙 \",\"🕚 \"]},\"earth\":{\"interval\":180,\"frames\":[\"🌍 \",\"🌎 \",\"🌏 \"]},\"moon\":{\"interval\":80,\"frames\":[\"🌑 \",\"🌒 \",\"🌓 \",\"🌔 \",\"🌕 \",\"🌖 \",\"🌗 \",\"🌘 \"]},\"runner\":{\"interval\":140,\"frames\":[\"🚶 \",\"🏃 \"]},\"pong\":{\"interval\":80,\"frames\":[\"▐⠂ ▌\",\"▐⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂▌\",\"▐ ⠠▌\",\"▐ ⡀▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐⠠ ▌\"]},\"shark\":{\"interval\":120,\"frames\":[\"▐|\\\\____________▌\",\"▐_|\\\\___________▌\",\"▐__|\\\\__________▌\",\"▐___|\\\\_________▌\",\"▐____|\\\\________▌\",\"▐_____|\\\\_______▌\",\"▐______|\\\\______▌\",\"▐_______|\\\\_____▌\",\"▐________|\\\\____▌\",\"▐_________|\\\\___▌\",\"▐__________|\\\\__▌\",\"▐___________|\\\\_▌\",\"▐____________|\\\\▌\",\"▐____________/|▌\",\"▐___________/|_▌\",\"▐__________/|__▌\",\"▐_________/|___▌\",\"▐________/|____▌\",\"▐_______/|_____▌\",\"▐______/|______▌\",\"▐_____/|_______▌\",\"▐____/|________▌\",\"▐___/|_________▌\",\"▐__/|__________▌\",\"▐_/|___________▌\",\"▐/|____________▌\"]},\"dqpb\":{\"interval\":100,\"frames\":[\"d\",\"q\",\"p\",\"b\"]},\"weather\":{\"interval\":100,\"frames\":[\"☀️ \",\"☀️ \",\"☀️ \",\"🌤 \",\"⛅️ \",\"🌥 \",\"☁️ \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"⛈ \",\"🌨 \",\"🌧 \",\"🌨 \",\"☁️ \",\"🌥 \",\"⛅️ \",\"🌤 \",\"☀️ \",\"☀️ \"]},\"christmas\":{\"interval\":400,\"frames\":[\"🌲\",\"🎄\"]}}"); /***/ }), -/* 686 */ +/* 687 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -78340,7 +78499,7 @@ const RunCommand = { }; /***/ }), -/* 687 */ +/* 688 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -78351,7 +78510,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(34); /* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(500); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(501); -/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(688); +/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(689); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -78435,7 +78594,7 @@ const WatchCommand = { }; /***/ }), -/* 688 */ +/* 689 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -78509,7 +78668,7 @@ function waitUntilWatchIsReady(stream, opts = {}) { } /***/ }), -/* 689 */ +/* 690 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -78517,15 +78676,15 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runCommand", function() { return runCommand; }); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(690); +/* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(691); /* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(indent_string__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(691); +/* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(692); /* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(wrap_ansi__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(515); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(34); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(501); -/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(698); -/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(699); +/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(699); +/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(700); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -78613,7 +78772,7 @@ function toArray(value) { } /***/ }), -/* 690 */ +/* 691 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78647,13 +78806,13 @@ module.exports = (str, count, opts) => { /***/ }), -/* 691 */ +/* 692 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringWidth = __webpack_require__(692); -const stripAnsi = __webpack_require__(696); +const stringWidth = __webpack_require__(693); +const stripAnsi = __webpack_require__(697); const ESCAPES = new Set([ '\u001B', @@ -78847,13 +79006,13 @@ module.exports = (str, cols, opts) => { /***/ }), -/* 692 */ +/* 693 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stripAnsi = __webpack_require__(693); -const isFullwidthCodePoint = __webpack_require__(695); +const stripAnsi = __webpack_require__(694); +const isFullwidthCodePoint = __webpack_require__(696); module.exports = str => { if (typeof str !== 'string' || str.length === 0) { @@ -78890,18 +79049,18 @@ module.exports = str => { /***/ }), -/* 693 */ +/* 694 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const ansiRegex = __webpack_require__(694); +const ansiRegex = __webpack_require__(695); module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; /***/ }), -/* 694 */ +/* 695 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78918,7 +79077,7 @@ module.exports = () => { /***/ }), -/* 695 */ +/* 696 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78971,18 +79130,18 @@ module.exports = x => { /***/ }), -/* 696 */ +/* 697 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const ansiRegex = __webpack_require__(697); +const ansiRegex = __webpack_require__(698); module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; /***/ }), -/* 697 */ +/* 698 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78999,7 +79158,7 @@ module.exports = () => { /***/ }), -/* 698 */ +/* 699 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -79152,7 +79311,7 @@ function addProjectToTree(tree, pathParts, project) { } /***/ }), -/* 699 */ +/* 700 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -79160,7 +79319,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Kibana", function() { return Kibana; }); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(16); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(700); +/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(701); /* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(multimatch__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(501); /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(579); @@ -79295,15 +79454,15 @@ class Kibana { } /***/ }), -/* 700 */ +/* 701 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const minimatch = __webpack_require__(505); -const arrayUnion = __webpack_require__(701); -const arrayDiffer = __webpack_require__(702); -const arrify = __webpack_require__(703); +const arrayUnion = __webpack_require__(702); +const arrayDiffer = __webpack_require__(703); +const arrify = __webpack_require__(704); module.exports = (list, patterns, options = {}) => { list = arrify(list); @@ -79327,7 +79486,7 @@ module.exports = (list, patterns, options = {}) => { /***/ }), -/* 701 */ +/* 702 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79339,7 +79498,7 @@ module.exports = (...arguments_) => { /***/ }), -/* 702 */ +/* 703 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79353,444 +79512,8 @@ const arrayDiffer = (array, ...values) => { module.exports = arrayDiffer; -/***/ }), -/* 703 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const arrify = value => { - if (value === null || value === undefined) { - return []; - } - - if (Array.isArray(value)) { - return value; - } - - if (typeof value === 'string') { - return [value]; - } - - if (typeof value[Symbol.iterator] === 'function') { - return [...value]; - } - - return [value]; -}; - -module.exports = arrify; - - /***/ }), /* 704 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(705); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; }); - -/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(928); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); - -/* - * 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. - */ - - - -/***/ }), -/* 705 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return buildProductionProjects; }); -/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(706); -/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(587); -/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(16); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(579); -/* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(20); -/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(34); -/* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(517); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(501); -/* - * 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. - */ - - - - - - - - -async function buildProductionProjects({ - kibanaRoot, - buildRoot, - onlyOSS -}) { - const projects = await getProductionProjects(kibanaRoot, onlyOSS); - const projectGraph = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["buildProjectGraph"])(projects); - const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["topologicallyBatchProjects"])(projects, projectGraph); - const projectNames = [...projects.values()].map(project => project.name); - _utils_log__WEBPACK_IMPORTED_MODULE_5__["log"].write(`Preparing production build for [${projectNames.join(', ')}]`); - - for (const batch of batchedProjects) { - for (const project of batch) { - await deleteTarget(project); - await buildProject(project); - await copyToBuild(project, kibanaRoot, buildRoot); - } - } -} -/** - * Returns the subset of projects that should be built into the production - * bundle. As we copy these into Kibana's `node_modules` during the build step, - * and let Kibana's build process be responsible for installing dependencies, - * we only include Kibana's transitive _production_ dependencies. If onlyOSS - * is supplied, we omit projects with build.oss in their package.json set to false. - */ - -async function getProductionProjects(rootPath, onlyOSS) { - const projectPaths = Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])({ - rootPath - }); - const projects = await Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["getProjects"])(rootPath, projectPaths); - const projectsSubset = [projects.get('kibana')]; - - if (projects.has('x-pack')) { - projectsSubset.push(projects.get('x-pack')); - } - - const productionProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["includeTransitiveProjects"])(projectsSubset, projects, { - onlyProductionDependencies: true - }); // We remove Kibana, as we're already building Kibana - - productionProjects.delete('kibana'); - - if (onlyOSS) { - productionProjects.forEach(project => { - if (project.getBuildConfig().oss === false) { - productionProjects.delete(project.json.name); - } - }); - } - - return productionProjects; -} - -async function deleteTarget(project) { - const targetDir = project.targetLocation; - - if (await Object(_utils_fs__WEBPACK_IMPORTED_MODULE_4__["isDirectory"])(targetDir)) { - await del__WEBPACK_IMPORTED_MODULE_1___default()(targetDir, { - force: true - }); - } -} - -async function buildProject(project) { - if (project.hasScript('build')) { - await project.runScript('build'); - } -} -/** - * Copy all the project's files from its "intermediate build directory" and - * into the build. The intermediate directory can either be the root of the - * project or some other location defined in the project's `package.json`. - * - * When copying all the files into the build, we exclude `node_modules` because - * we want the Kibana build to be responsible for actually installing all - * dependencies. The primary reason for allowing the Kibana build process to - * manage dependencies is that it will "dedupe" them, so we don't include - * unnecessary copies of dependencies. - */ - - -async function copyToBuild(project, kibanaRoot, buildRoot) { - // We want the package to have the same relative location within the build - const relativeProjectPath = Object(path__WEBPACK_IMPORTED_MODULE_2__["relative"])(kibanaRoot, project.path); - const buildProjectPath = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(buildRoot, relativeProjectPath); - await cpy__WEBPACK_IMPORTED_MODULE_0___default()(['**/*', '!node_modules/**'], buildProjectPath, { - cwd: project.getIntermediateBuildDirectory(), - dot: true, - nodir: true, - parents: true - }); // If a project is using an intermediate build directory, we special-case our - // handling of `package.json`, as the project build process might have copied - // (a potentially modified) `package.json` into the intermediate build - // directory already. If so, we want to use that `package.json` as the basis - // for creating the production-ready `package.json`. If it's not present in - // the intermediate build, we fall back to using the project's already defined - // `package.json`. - - const packageJson = (await Object(_utils_fs__WEBPACK_IMPORTED_MODULE_4__["isFile"])(Object(path__WEBPACK_IMPORTED_MODULE_2__["join"])(buildProjectPath, 'package.json'))) ? await Object(_utils_package_json__WEBPACK_IMPORTED_MODULE_6__["readPackageJson"])(buildProjectPath) : project.json; - await Object(_utils_package_json__WEBPACK_IMPORTED_MODULE_6__["writePackageJson"])(buildProjectPath, packageJson); -} - -/***/ }), -/* 706 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const EventEmitter = __webpack_require__(379); -const path = __webpack_require__(16); -const os = __webpack_require__(11); -const pAll = __webpack_require__(707); -const arrify = __webpack_require__(709); -const globby = __webpack_require__(710); -const isGlob = __webpack_require__(605); -const cpFile = __webpack_require__(913); -const junk = __webpack_require__(925); -const CpyError = __webpack_require__(926); - -const defaultOptions = { - ignoreJunk: true -}; - -const preprocessSourcePath = (source, options) => options.cwd ? path.resolve(options.cwd, source) : source; - -const preprocessDestinationPath = (source, destination, options) => { - let basename = path.basename(source); - const dirname = path.dirname(source); - - if (typeof options.rename === 'string') { - basename = options.rename; - } else if (typeof options.rename === 'function') { - basename = options.rename(basename); - } - - if (options.cwd) { - destination = path.resolve(options.cwd, destination); - } - - if (options.parents) { - return path.join(destination, dirname, basename); - } - - return path.join(destination, basename); -}; - -module.exports = (source, destination, { - concurrency = (os.cpus().length || 1) * 2, - ...options -} = {}) => { - const progressEmitter = new EventEmitter(); - - options = { - ...defaultOptions, - ...options - }; - - const promise = (async () => { - source = arrify(source); - - if (source.length === 0 || !destination) { - throw new CpyError('`source` and `destination` required'); - } - - const copyStatus = new Map(); - let completedFiles = 0; - let completedSize = 0; - - let files; - try { - files = await globby(source, options); - - if (options.ignoreJunk) { - files = files.filter(file => junk.not(path.basename(file))); - } - } catch (error) { - throw new CpyError(`Cannot glob \`${source}\`: ${error.message}`, error); - } - - const sourcePaths = source.filter(value => !isGlob(value)); - - if (files.length === 0 || (sourcePaths.length > 0 && !sourcePaths.every(value => files.includes(value)))) { - throw new CpyError(`Cannot copy \`${source}\`: the file doesn't exist`); - } - - const fileProgressHandler = event => { - const fileStatus = copyStatus.get(event.src) || {written: 0, percent: 0}; - - if (fileStatus.written !== event.written || fileStatus.percent !== event.percent) { - completedSize -= fileStatus.written; - completedSize += event.written; - - if (event.percent === 1 && fileStatus.percent !== 1) { - completedFiles++; - } - - copyStatus.set(event.src, { - written: event.written, - percent: event.percent - }); - - progressEmitter.emit('progress', { - totalFiles: files.length, - percent: completedFiles / files.length, - completedFiles, - completedSize - }); - } - }; - - return pAll(files.map(sourcePath => { - return async () => { - const from = preprocessSourcePath(sourcePath, options); - const to = preprocessDestinationPath(sourcePath, destination, options); - - try { - await cpFile(from, to, options).on('progress', fileProgressHandler); - } catch (error) { - throw new CpyError(`Cannot copy from \`${from}\` to \`${to}\`: ${error.message}`, error); - } - - return to; - }; - }), {concurrency}); - })(); - - promise.on = (...arguments_) => { - progressEmitter.on(...arguments_); - return promise; - }; - - return promise; -}; - - -/***/ }), -/* 707 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const pMap = __webpack_require__(708); - -module.exports = (iterable, options) => pMap(iterable, element => element(), options); -// TODO: Remove this for the next major release -module.exports.default = module.exports; - - -/***/ }), -/* 708 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const pMap = (iterable, mapper, options) => new Promise((resolve, reject) => { - options = Object.assign({ - concurrency: Infinity - }, options); - - if (typeof mapper !== 'function') { - throw new TypeError('Mapper function is required'); - } - - const {concurrency} = options; - - if (!(typeof concurrency === 'number' && concurrency >= 1)) { - throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); - } - - const ret = []; - const iterator = iterable[Symbol.iterator](); - let isRejected = false; - let isIterableDone = false; - let resolvingCount = 0; - let currentIndex = 0; - - const next = () => { - if (isRejected) { - return; - } - - const nextItem = iterator.next(); - const i = currentIndex; - currentIndex++; - - if (nextItem.done) { - isIterableDone = true; - - if (resolvingCount === 0) { - resolve(ret); - } - - return; - } - - resolvingCount++; - - Promise.resolve(nextItem.value) - .then(element => mapper(element, i)) - .then( - value => { - ret[i] = value; - resolvingCount--; - next(); - }, - error => { - isRejected = true; - reject(error); - } - ); - }; - - for (let i = 0; i < concurrency; i++) { - next(); - - if (isIterableDone) { - break; - } - } -}); - -module.exports = pMap; -// TODO: Remove this for the next major release -module.exports.default = pMap; - - -/***/ }), -/* 709 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79819,18 +79542,454 @@ const arrify = value => { module.exports = arrify; +/***/ }), +/* 705 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(706); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; }); + +/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(741); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); + +/* + * 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. + */ + + + +/***/ }), +/* 706 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return buildProductionProjects; }); +/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(707); +/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(587); +/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(16); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(579); +/* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(20); +/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(34); +/* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(517); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(501); +/* + * 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. + */ + + + + + + + + +async function buildProductionProjects({ + kibanaRoot, + buildRoot, + onlyOSS +}) { + const projects = await getProductionProjects(kibanaRoot, onlyOSS); + const projectGraph = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["buildProjectGraph"])(projects); + const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["topologicallyBatchProjects"])(projects, projectGraph); + const projectNames = [...projects.values()].map(project => project.name); + _utils_log__WEBPACK_IMPORTED_MODULE_5__["log"].write(`Preparing production build for [${projectNames.join(', ')}]`); + + for (const batch of batchedProjects) { + for (const project of batch) { + await deleteTarget(project); + await buildProject(project); + await copyToBuild(project, kibanaRoot, buildRoot); + } + } +} +/** + * Returns the subset of projects that should be built into the production + * bundle. As we copy these into Kibana's `node_modules` during the build step, + * and let Kibana's build process be responsible for installing dependencies, + * we only include Kibana's transitive _production_ dependencies. If onlyOSS + * is supplied, we omit projects with build.oss in their package.json set to false. + */ + +async function getProductionProjects(rootPath, onlyOSS) { + const projectPaths = Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])({ + rootPath + }); + const projects = await Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["getProjects"])(rootPath, projectPaths); + const projectsSubset = [projects.get('kibana')]; + + if (projects.has('x-pack')) { + projectsSubset.push(projects.get('x-pack')); + } + + const productionProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["includeTransitiveProjects"])(projectsSubset, projects, { + onlyProductionDependencies: true + }); // We remove Kibana, as we're already building Kibana + + productionProjects.delete('kibana'); + + if (onlyOSS) { + productionProjects.forEach(project => { + if (project.getBuildConfig().oss === false) { + productionProjects.delete(project.json.name); + } + }); + } + + return productionProjects; +} + +async function deleteTarget(project) { + const targetDir = project.targetLocation; + + if (await Object(_utils_fs__WEBPACK_IMPORTED_MODULE_4__["isDirectory"])(targetDir)) { + await del__WEBPACK_IMPORTED_MODULE_1___default()(targetDir, { + force: true + }); + } +} + +async function buildProject(project) { + if (project.hasScript('build')) { + await project.runScript('build'); + } +} +/** + * Copy all the project's files from its "intermediate build directory" and + * into the build. The intermediate directory can either be the root of the + * project or some other location defined in the project's `package.json`. + * + * When copying all the files into the build, we exclude `node_modules` because + * we want the Kibana build to be responsible for actually installing all + * dependencies. The primary reason for allowing the Kibana build process to + * manage dependencies is that it will "dedupe" them, so we don't include + * unnecessary copies of dependencies. + */ + + +async function copyToBuild(project, kibanaRoot, buildRoot) { + // We want the package to have the same relative location within the build + const relativeProjectPath = Object(path__WEBPACK_IMPORTED_MODULE_2__["relative"])(kibanaRoot, project.path); + const buildProjectPath = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(buildRoot, relativeProjectPath); + await cpy__WEBPACK_IMPORTED_MODULE_0___default()(['**/*', '!node_modules/**'], buildProjectPath, { + cwd: project.getIntermediateBuildDirectory(), + dot: true, + nodir: true, + parents: true + }); // If a project is using an intermediate build directory, we special-case our + // handling of `package.json`, as the project build process might have copied + // (a potentially modified) `package.json` into the intermediate build + // directory already. If so, we want to use that `package.json` as the basis + // for creating the production-ready `package.json`. If it's not present in + // the intermediate build, we fall back to using the project's already defined + // `package.json`. + + const packageJson = (await Object(_utils_fs__WEBPACK_IMPORTED_MODULE_4__["isFile"])(Object(path__WEBPACK_IMPORTED_MODULE_2__["join"])(buildProjectPath, 'package.json'))) ? await Object(_utils_package_json__WEBPACK_IMPORTED_MODULE_6__["readPackageJson"])(buildProjectPath) : project.json; + await Object(_utils_package_json__WEBPACK_IMPORTED_MODULE_6__["writePackageJson"])(buildProjectPath, packageJson); +} + +/***/ }), +/* 707 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const EventEmitter = __webpack_require__(379); +const path = __webpack_require__(16); +const os = __webpack_require__(11); +const pAll = __webpack_require__(708); +const arrify = __webpack_require__(710); +const globby = __webpack_require__(711); +const isGlob = __webpack_require__(605); +const cpFile = __webpack_require__(726); +const junk = __webpack_require__(738); +const CpyError = __webpack_require__(739); + +const defaultOptions = { + ignoreJunk: true +}; + +const preprocessSourcePath = (source, options) => options.cwd ? path.resolve(options.cwd, source) : source; + +const preprocessDestinationPath = (source, destination, options) => { + let basename = path.basename(source); + const dirname = path.dirname(source); + + if (typeof options.rename === 'string') { + basename = options.rename; + } else if (typeof options.rename === 'function') { + basename = options.rename(basename); + } + + if (options.cwd) { + destination = path.resolve(options.cwd, destination); + } + + if (options.parents) { + return path.join(destination, dirname, basename); + } + + return path.join(destination, basename); +}; + +module.exports = (source, destination, { + concurrency = (os.cpus().length || 1) * 2, + ...options +} = {}) => { + const progressEmitter = new EventEmitter(); + + options = { + ...defaultOptions, + ...options + }; + + const promise = (async () => { + source = arrify(source); + + if (source.length === 0 || !destination) { + throw new CpyError('`source` and `destination` required'); + } + + const copyStatus = new Map(); + let completedFiles = 0; + let completedSize = 0; + + let files; + try { + files = await globby(source, options); + + if (options.ignoreJunk) { + files = files.filter(file => junk.not(path.basename(file))); + } + } catch (error) { + throw new CpyError(`Cannot glob \`${source}\`: ${error.message}`, error); + } + + const sourcePaths = source.filter(value => !isGlob(value)); + + if (files.length === 0 || (sourcePaths.length > 0 && !sourcePaths.every(value => files.includes(value)))) { + throw new CpyError(`Cannot copy \`${source}\`: the file doesn't exist`); + } + + const fileProgressHandler = event => { + const fileStatus = copyStatus.get(event.src) || {written: 0, percent: 0}; + + if (fileStatus.written !== event.written || fileStatus.percent !== event.percent) { + completedSize -= fileStatus.written; + completedSize += event.written; + + if (event.percent === 1 && fileStatus.percent !== 1) { + completedFiles++; + } + + copyStatus.set(event.src, { + written: event.written, + percent: event.percent + }); + + progressEmitter.emit('progress', { + totalFiles: files.length, + percent: completedFiles / files.length, + completedFiles, + completedSize + }); + } + }; + + return pAll(files.map(sourcePath => { + return async () => { + const from = preprocessSourcePath(sourcePath, options); + const to = preprocessDestinationPath(sourcePath, destination, options); + + try { + await cpFile(from, to, options).on('progress', fileProgressHandler); + } catch (error) { + throw new CpyError(`Cannot copy from \`${from}\` to \`${to}\`: ${error.message}`, error); + } + + return to; + }; + }), {concurrency}); + })(); + + promise.on = (...arguments_) => { + progressEmitter.on(...arguments_); + return promise; + }; + + return promise; +}; + + +/***/ }), +/* 708 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const pMap = __webpack_require__(709); + +module.exports = (iterable, options) => pMap(iterable, element => element(), options); +// TODO: Remove this for the next major release +module.exports.default = module.exports; + + +/***/ }), +/* 709 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const pMap = (iterable, mapper, options) => new Promise((resolve, reject) => { + options = Object.assign({ + concurrency: Infinity + }, options); + + if (typeof mapper !== 'function') { + throw new TypeError('Mapper function is required'); + } + + const {concurrency} = options; + + if (!(typeof concurrency === 'number' && concurrency >= 1)) { + throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); + } + + const ret = []; + const iterator = iterable[Symbol.iterator](); + let isRejected = false; + let isIterableDone = false; + let resolvingCount = 0; + let currentIndex = 0; + + const next = () => { + if (isRejected) { + return; + } + + const nextItem = iterator.next(); + const i = currentIndex; + currentIndex++; + + if (nextItem.done) { + isIterableDone = true; + + if (resolvingCount === 0) { + resolve(ret); + } + + return; + } + + resolvingCount++; + + Promise.resolve(nextItem.value) + .then(element => mapper(element, i)) + .then( + value => { + ret[i] = value; + resolvingCount--; + next(); + }, + error => { + isRejected = true; + reject(error); + } + ); + }; + + for (let i = 0; i < concurrency; i++) { + next(); + + if (isIterableDone) { + break; + } + } +}); + +module.exports = pMap; +// TODO: Remove this for the next major release +module.exports.default = pMap; + + /***/ }), /* 710 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; + +const arrify = value => { + if (value === null || value === undefined) { + return []; + } + + if (Array.isArray(value)) { + return value; + } + + if (typeof value === 'string') { + return [value]; + } + + if (typeof value[Symbol.iterator] === 'function') { + return [...value]; + } + + return [value]; +}; + +module.exports = arrify; + + +/***/ }), +/* 711 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + const fs = __webpack_require__(23); -const arrayUnion = __webpack_require__(711); -const glob = __webpack_require__(713); -const fastGlob = __webpack_require__(718); -const dirGlob = __webpack_require__(906); -const gitignore = __webpack_require__(909); +const arrayUnion = __webpack_require__(712); +const glob = __webpack_require__(714); +const fastGlob = __webpack_require__(596); +const dirGlob = __webpack_require__(719); +const gitignore = __webpack_require__(722); const DEFAULT_FILTER = () => false; @@ -79975,12 +80134,12 @@ module.exports.gitignore = gitignore; /***/ }), -/* 711 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var arrayUniq = __webpack_require__(712); +var arrayUniq = __webpack_require__(713); module.exports = function () { return arrayUniq([].concat.apply([], arguments)); @@ -79988,7 +80147,7 @@ module.exports = function () { /***/ }), -/* 712 */ +/* 713 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80057,7 +80216,7 @@ if ('Set' in global) { /***/ }), -/* 713 */ +/* 714 */ /***/ (function(module, exports, __webpack_require__) { // Approach: @@ -80106,13 +80265,13 @@ var fs = __webpack_require__(23) var rp = __webpack_require__(503) var minimatch = __webpack_require__(505) var Minimatch = minimatch.Minimatch -var inherits = __webpack_require__(714) +var inherits = __webpack_require__(715) var EE = __webpack_require__(379).EventEmitter var path = __webpack_require__(16) var assert = __webpack_require__(30) var isAbsolute = __webpack_require__(511) -var globSync = __webpack_require__(716) -var common = __webpack_require__(717) +var globSync = __webpack_require__(717) +var common = __webpack_require__(718) var alphasort = common.alphasort var alphasorti = common.alphasorti var setopts = common.setopts @@ -80853,7 +81012,7 @@ Glob.prototype._stat2 = function (f, abs, er, stat, cb) { /***/ }), -/* 714 */ +/* 715 */ /***/ (function(module, exports, __webpack_require__) { try { @@ -80863,12 +81022,12 @@ try { module.exports = util.inherits; } catch (e) { /* istanbul ignore next */ - module.exports = __webpack_require__(715); + module.exports = __webpack_require__(716); } /***/ }), -/* 715 */ +/* 716 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { @@ -80901,7 +81060,7 @@ if (typeof Object.create === 'function') { /***/ }), -/* 716 */ +/* 717 */ /***/ (function(module, exports, __webpack_require__) { module.exports = globSync @@ -80911,12 +81070,12 @@ var fs = __webpack_require__(23) var rp = __webpack_require__(503) var minimatch = __webpack_require__(505) var Minimatch = minimatch.Minimatch -var Glob = __webpack_require__(713).Glob +var Glob = __webpack_require__(714).Glob var util = __webpack_require__(29) var path = __webpack_require__(16) var assert = __webpack_require__(30) var isAbsolute = __webpack_require__(511) -var common = __webpack_require__(717) +var common = __webpack_require__(718) var alphasort = common.alphasort var alphasorti = common.alphasorti var setopts = common.setopts @@ -81342,24464 +81501,310 @@ GlobSync.prototype._stat = function (f) { return false // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. - } - - var exists - var stat = this.statCache[abs] - if (!stat) { - var lstat - try { - lstat = fs.lstatSync(abs) - } catch (er) { - if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { - this.statCache[abs] = false - return false - } - } - - if (lstat && lstat.isSymbolicLink()) { - try { - stat = fs.statSync(abs) - } catch (er) { - stat = lstat - } - } else { - stat = lstat - } - } - - this.statCache[abs] = stat - - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' - - this.cache[abs] = this.cache[abs] || c - - if (needDir && c === 'FILE') - return false - - return c -} - -GlobSync.prototype._mark = function (p) { - return common.mark(this, p) -} - -GlobSync.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} - - -/***/ }), -/* 717 */ -/***/ (function(module, exports, __webpack_require__) { - -exports.alphasort = alphasort -exports.alphasorti = alphasorti -exports.setopts = setopts -exports.ownProp = ownProp -exports.makeAbs = makeAbs -exports.finish = finish -exports.mark = mark -exports.isIgnored = isIgnored -exports.childrenIgnored = childrenIgnored - -function ownProp (obj, field) { - return Object.prototype.hasOwnProperty.call(obj, field) -} - -var path = __webpack_require__(16) -var minimatch = __webpack_require__(505) -var isAbsolute = __webpack_require__(511) -var Minimatch = minimatch.Minimatch - -function alphasorti (a, b) { - return a.toLowerCase().localeCompare(b.toLowerCase()) -} - -function alphasort (a, b) { - return a.localeCompare(b) -} - -function setupIgnores (self, options) { - self.ignore = options.ignore || [] - - if (!Array.isArray(self.ignore)) - self.ignore = [self.ignore] - - if (self.ignore.length) { - self.ignore = self.ignore.map(ignoreMap) - } -} - -// ignore patterns are always in dot:true mode. -function ignoreMap (pattern) { - var gmatcher = null - if (pattern.slice(-3) === '/**') { - var gpattern = pattern.replace(/(\/\*\*)+$/, '') - gmatcher = new Minimatch(gpattern, { dot: true }) - } - - return { - matcher: new Minimatch(pattern, { dot: true }), - gmatcher: gmatcher - } -} - -function setopts (self, pattern, options) { - if (!options) - options = {} - - // base-matching: just use globstar for that. - if (options.matchBase && -1 === pattern.indexOf("/")) { - if (options.noglobstar) { - throw new Error("base matching requires globstar") - } - pattern = "**/" + pattern - } - - self.silent = !!options.silent - self.pattern = pattern - self.strict = options.strict !== false - self.realpath = !!options.realpath - self.realpathCache = options.realpathCache || Object.create(null) - self.follow = !!options.follow - self.dot = !!options.dot - self.mark = !!options.mark - self.nodir = !!options.nodir - if (self.nodir) - self.mark = true - self.sync = !!options.sync - self.nounique = !!options.nounique - self.nonull = !!options.nonull - self.nosort = !!options.nosort - self.nocase = !!options.nocase - self.stat = !!options.stat - self.noprocess = !!options.noprocess - self.absolute = !!options.absolute - - self.maxLength = options.maxLength || Infinity - self.cache = options.cache || Object.create(null) - self.statCache = options.statCache || Object.create(null) - self.symlinks = options.symlinks || Object.create(null) - - setupIgnores(self, options) - - self.changedCwd = false - var cwd = process.cwd() - if (!ownProp(options, "cwd")) - self.cwd = cwd - else { - self.cwd = path.resolve(options.cwd) - self.changedCwd = self.cwd !== cwd - } - - self.root = options.root || path.resolve(self.cwd, "/") - self.root = path.resolve(self.root) - if (process.platform === "win32") - self.root = self.root.replace(/\\/g, "/") - - // TODO: is an absolute `cwd` supposed to be resolved against `root`? - // e.g. { cwd: '/test', root: __dirname } === path.join(__dirname, '/test') - self.cwdAbs = isAbsolute(self.cwd) ? self.cwd : makeAbs(self, self.cwd) - if (process.platform === "win32") - self.cwdAbs = self.cwdAbs.replace(/\\/g, "/") - self.nomount = !!options.nomount - - // disable comments and negation in Minimatch. - // Note that they are not supported in Glob itself anyway. - options.nonegate = true - options.nocomment = true - - self.minimatch = new Minimatch(pattern, options) - self.options = self.minimatch.options -} - -function finish (self) { - var nou = self.nounique - var all = nou ? [] : Object.create(null) - - for (var i = 0, l = self.matches.length; i < l; i ++) { - var matches = self.matches[i] - if (!matches || Object.keys(matches).length === 0) { - if (self.nonull) { - // do like the shell, and spit out the literal glob - var literal = self.minimatch.globSet[i] - if (nou) - all.push(literal) - else - all[literal] = true - } - } else { - // had matches - var m = Object.keys(matches) - if (nou) - all.push.apply(all, m) - else - m.forEach(function (m) { - all[m] = true - }) - } - } - - if (!nou) - all = Object.keys(all) - - if (!self.nosort) - all = all.sort(self.nocase ? alphasorti : alphasort) - - // at *some* point we statted all of these - if (self.mark) { - for (var i = 0; i < all.length; i++) { - all[i] = self._mark(all[i]) - } - if (self.nodir) { - all = all.filter(function (e) { - var notDir = !(/\/$/.test(e)) - var c = self.cache[e] || self.cache[makeAbs(self, e)] - if (notDir && c) - notDir = c !== 'DIR' && !Array.isArray(c) - return notDir - }) - } - } - - if (self.ignore.length) - all = all.filter(function(m) { - return !isIgnored(self, m) - }) - - self.found = all -} - -function mark (self, p) { - var abs = makeAbs(self, p) - var c = self.cache[abs] - var m = p - if (c) { - var isDir = c === 'DIR' || Array.isArray(c) - var slash = p.slice(-1) === '/' - - if (isDir && !slash) - m += '/' - else if (!isDir && slash) - m = m.slice(0, -1) - - if (m !== p) { - var mabs = makeAbs(self, m) - self.statCache[mabs] = self.statCache[abs] - self.cache[mabs] = self.cache[abs] - } - } - - return m -} - -// lotta situps... -function makeAbs (self, f) { - var abs = f - if (f.charAt(0) === '/') { - abs = path.join(self.root, f) - } else if (isAbsolute(f) || f === '') { - abs = f - } else if (self.changedCwd) { - abs = path.resolve(self.cwd, f) - } else { - abs = path.resolve(f) - } - - if (process.platform === 'win32') - abs = abs.replace(/\\/g, '/') - - return abs -} - - -// Return true, if pattern ends with globstar '**', for the accompanying parent directory. -// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents -function isIgnored (self, path) { - if (!self.ignore.length) - return false - - return self.ignore.some(function(item) { - return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) - }) -} - -function childrenIgnored (self, path) { - if (!self.ignore.length) - return false - - return self.ignore.some(function(item) { - return !!(item.gmatcher && item.gmatcher.match(path)) - }) -} - - -/***/ }), -/* 718 */ -/***/ (function(module, exports, __webpack_require__) { - -const pkg = __webpack_require__(719); - -module.exports = pkg.async; -module.exports.default = pkg.async; - -module.exports.async = pkg.async; -module.exports.sync = pkg.sync; -module.exports.stream = pkg.stream; - -module.exports.generateTasks = pkg.generateTasks; - - -/***/ }), -/* 719 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(720); -var taskManager = __webpack_require__(721); -var reader_async_1 = __webpack_require__(877); -var reader_stream_1 = __webpack_require__(901); -var reader_sync_1 = __webpack_require__(902); -var arrayUtils = __webpack_require__(904); -var streamUtils = __webpack_require__(905); -/** - * Synchronous API. - */ -function sync(source, opts) { - assertPatternsInput(source); - var works = getWorks(source, reader_sync_1.default, opts); - return arrayUtils.flatten(works); -} -exports.sync = sync; -/** - * Asynchronous API. - */ -function async(source, opts) { - try { - assertPatternsInput(source); - } - catch (error) { - return Promise.reject(error); - } - var works = getWorks(source, reader_async_1.default, opts); - return Promise.all(works).then(arrayUtils.flatten); -} -exports.async = async; -/** - * Stream API. - */ -function stream(source, opts) { - assertPatternsInput(source); - var works = getWorks(source, reader_stream_1.default, opts); - return streamUtils.merge(works); -} -exports.stream = stream; -/** - * Return a set of tasks based on provided patterns. - */ -function generateTasks(source, opts) { - assertPatternsInput(source); - var patterns = [].concat(source); - var options = optionsManager.prepare(opts); - return taskManager.generate(patterns, options); -} -exports.generateTasks = generateTasks; -/** - * Returns a set of works based on provided tasks and class of the reader. - */ -function getWorks(source, _Reader, opts) { - var patterns = [].concat(source); - var options = optionsManager.prepare(opts); - var tasks = taskManager.generate(patterns, options); - var reader = new _Reader(options); - return tasks.map(reader.read, reader); -} -function assertPatternsInput(source) { - if ([].concat(source).every(isString)) { - return; - } - throw new TypeError('Patterns must be a string or an array of strings'); -} -function isString(source) { - /* tslint:disable-next-line strict-type-predicates */ - return typeof source === 'string'; -} - - -/***/ }), -/* 720 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -function prepare(options) { - var opts = __assign({ cwd: process.cwd(), deep: true, ignore: [], dot: false, stats: false, onlyFiles: true, onlyDirectories: false, followSymlinkedDirectories: true, unique: true, markDirectories: false, absolute: false, nobrace: false, brace: true, noglobstar: false, globstar: true, noext: false, extension: true, nocase: false, case: true, matchBase: false, transform: null }, options); - if (opts.onlyDirectories) { - opts.onlyFiles = false; - } - opts.brace = !opts.nobrace; - opts.globstar = !opts.noglobstar; - opts.extension = !opts.noext; - opts.case = !opts.nocase; - if (options) { - opts.brace = ('brace' in options ? options.brace : opts.brace); - opts.globstar = ('globstar' in options ? options.globstar : opts.globstar); - opts.extension = ('extension' in options ? options.extension : opts.extension); - opts.case = ('case' in options ? options.case : opts.case); - } - return opts; -} -exports.prepare = prepare; - - -/***/ }), -/* 721 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(722); -/** - * Generate tasks based on parent directory of each pattern. - */ -function generate(patterns, options) { - var unixPatterns = patterns.map(patternUtils.unixifyPattern); - var unixIgnore = options.ignore.map(patternUtils.unixifyPattern); - var positivePatterns = getPositivePatterns(unixPatterns); - var negativePatterns = getNegativePatternsAsPositive(unixPatterns, unixIgnore); - /** - * When the `case` option is disabled, all patterns must be marked as dynamic, because we cannot check filepath - * directly (without read directory). - */ - var staticPatterns = !options.case ? [] : positivePatterns.filter(patternUtils.isStaticPattern); - var dynamicPatterns = !options.case ? positivePatterns : positivePatterns.filter(patternUtils.isDynamicPattern); - var staticTasks = convertPatternsToTasks(staticPatterns, negativePatterns, /* dynamic */ false); - var dynamicTasks = convertPatternsToTasks(dynamicPatterns, negativePatterns, /* dynamic */ true); - return staticTasks.concat(dynamicTasks); -} -exports.generate = generate; -/** - * Convert patterns to tasks based on parent directory of each pattern. - */ -function convertPatternsToTasks(positive, negative, dynamic) { - var positivePatternsGroup = groupPatternsByBaseDirectory(positive); - // When we have a global group – there is no reason to divide the patterns into independent tasks. - // In this case, the global task covers the rest. - if ('.' in positivePatternsGroup) { - var task = convertPatternGroupToTask('.', positive, negative, dynamic); - return [task]; - } - return convertPatternGroupsToTasks(positivePatternsGroup, negative, dynamic); -} -exports.convertPatternsToTasks = convertPatternsToTasks; -/** - * Return only positive patterns. - */ -function getPositivePatterns(patterns) { - return patternUtils.getPositivePatterns(patterns); -} -exports.getPositivePatterns = getPositivePatterns; -/** - * Return only negative patterns. - */ -function getNegativePatternsAsPositive(patterns, ignore) { - var negative = patternUtils.getNegativePatterns(patterns).concat(ignore); - var positive = negative.map(patternUtils.convertToPositivePattern); - return positive; -} -exports.getNegativePatternsAsPositive = getNegativePatternsAsPositive; -/** - * Group patterns by base directory of each pattern. - */ -function groupPatternsByBaseDirectory(patterns) { - return patterns.reduce(function (collection, pattern) { - var base = patternUtils.getBaseDirectory(pattern); - if (base in collection) { - collection[base].push(pattern); - } - else { - collection[base] = [pattern]; - } - return collection; - }, {}); -} -exports.groupPatternsByBaseDirectory = groupPatternsByBaseDirectory; -/** - * Convert group of patterns to tasks. - */ -function convertPatternGroupsToTasks(positive, negative, dynamic) { - return Object.keys(positive).map(function (base) { - return convertPatternGroupToTask(base, positive[base], negative, dynamic); - }); -} -exports.convertPatternGroupsToTasks = convertPatternGroupsToTasks; -/** - * Create a task for positive and negative patterns. - */ -function convertPatternGroupToTask(base, positive, negative, dynamic) { - return { - base: base, - dynamic: dynamic, - positive: positive, - negative: negative, - patterns: [].concat(positive, negative.map(patternUtils.convertToNegativePattern)) - }; -} -exports.convertPatternGroupToTask = convertPatternGroupToTask; - - -/***/ }), -/* 722 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(16); -var globParent = __webpack_require__(723); -var isGlob = __webpack_require__(726); -var micromatch = __webpack_require__(727); -var GLOBSTAR = '**'; -/** - * Return true for static pattern. - */ -function isStaticPattern(pattern) { - return !isDynamicPattern(pattern); -} -exports.isStaticPattern = isStaticPattern; -/** - * Return true for pattern that looks like glob. - */ -function isDynamicPattern(pattern) { - return isGlob(pattern, { strict: false }); -} -exports.isDynamicPattern = isDynamicPattern; -/** - * Convert a windows «path» to a unix-style «path». - */ -function unixifyPattern(pattern) { - return pattern.replace(/\\/g, '/'); -} -exports.unixifyPattern = unixifyPattern; -/** - * Returns negative pattern as positive pattern. - */ -function convertToPositivePattern(pattern) { - return isNegativePattern(pattern) ? pattern.slice(1) : pattern; -} -exports.convertToPositivePattern = convertToPositivePattern; -/** - * Returns positive pattern as negative pattern. - */ -function convertToNegativePattern(pattern) { - return '!' + pattern; -} -exports.convertToNegativePattern = convertToNegativePattern; -/** - * Return true if provided pattern is negative pattern. - */ -function isNegativePattern(pattern) { - return pattern.startsWith('!') && pattern[1] !== '('; -} -exports.isNegativePattern = isNegativePattern; -/** - * Return true if provided pattern is positive pattern. - */ -function isPositivePattern(pattern) { - return !isNegativePattern(pattern); -} -exports.isPositivePattern = isPositivePattern; -/** - * Extracts negative patterns from array of patterns. - */ -function getNegativePatterns(patterns) { - return patterns.filter(isNegativePattern); -} -exports.getNegativePatterns = getNegativePatterns; -/** - * Extracts positive patterns from array of patterns. - */ -function getPositivePatterns(patterns) { - return patterns.filter(isPositivePattern); -} -exports.getPositivePatterns = getPositivePatterns; -/** - * Extract base directory from provided pattern. - */ -function getBaseDirectory(pattern) { - return globParent(pattern); -} -exports.getBaseDirectory = getBaseDirectory; -/** - * Return true if provided pattern has globstar. - */ -function hasGlobStar(pattern) { - return pattern.indexOf(GLOBSTAR) !== -1; -} -exports.hasGlobStar = hasGlobStar; -/** - * Return true if provided pattern ends with slash and globstar. - */ -function endsWithSlashGlobStar(pattern) { - return pattern.endsWith('/' + GLOBSTAR); -} -exports.endsWithSlashGlobStar = endsWithSlashGlobStar; -/** - * Returns «true» when pattern ends with a slash and globstar or the last partial of the pattern is static pattern. - */ -function isAffectDepthOfReadingPattern(pattern) { - var basename = path.basename(pattern); - return endsWithSlashGlobStar(pattern) || isStaticPattern(basename); -} -exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern; -/** - * Return naive depth of provided pattern without depth of the base directory. - */ -function getNaiveDepth(pattern) { - var base = getBaseDirectory(pattern); - var patternDepth = pattern.split('/').length; - var patternBaseDepth = base.split('/').length; - /** - * This is a hack for pattern that has no base directory. - * - * This is related to the `*\something\*` pattern. - */ - if (base === '.') { - return patternDepth - patternBaseDepth; - } - return patternDepth - patternBaseDepth - 1; -} -exports.getNaiveDepth = getNaiveDepth; -/** - * Return max naive depth of provided patterns without depth of the base directory. - */ -function getMaxNaivePatternsDepth(patterns) { - return patterns.reduce(function (max, pattern) { - var depth = getNaiveDepth(pattern); - return depth > max ? depth : max; - }, 0); -} -exports.getMaxNaivePatternsDepth = getMaxNaivePatternsDepth; -/** - * Make RegExp for provided pattern. - */ -function makeRe(pattern, options) { - return micromatch.makeRe(pattern, options); -} -exports.makeRe = makeRe; -/** - * Convert patterns to regexps. - */ -function convertPatternsToRe(patterns, options) { - return patterns.map(function (pattern) { return makeRe(pattern, options); }); -} -exports.convertPatternsToRe = convertPatternsToRe; -/** - * Returns true if the entry match any of the given RegExp's. - */ -function matchAny(entry, patternsRe) { - return patternsRe.some(function (patternRe) { return patternRe.test(entry); }); -} -exports.matchAny = matchAny; - - -/***/ }), -/* 723 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var path = __webpack_require__(16); -var isglob = __webpack_require__(724); -var pathDirname = __webpack_require__(725); -var isWin32 = __webpack_require__(11).platform() === 'win32'; - -module.exports = function globParent(str) { - // flip windows path separators - if (isWin32 && str.indexOf('/') < 0) str = str.split('\\').join('/'); - - // special case for strings ending in enclosure containing path separator - if (/[\{\[].*[\/]*.*[\}\]]$/.test(str)) str += '/'; - - // preserves full path in case of trailing path separator - str += 'a'; - - // remove path parts that are globby - do {str = pathDirname.posix(str)} - while (isglob(str) || /(^|[^\\])([\{\[]|\([^\)]+$)/.test(str)); - - // remove escape chars and return result - return str.replace(/\\([\*\?\|\[\]\(\)\{\}])/g, '$1'); -}; - - -/***/ }), -/* 724 */ -/***/ (function(module, exports, __webpack_require__) { - -/*! - * is-glob - * - * Copyright (c) 2014-2016, Jon Schlinkert. - * Licensed under the MIT License. - */ - -var isExtglob = __webpack_require__(606); - -module.exports = function isGlob(str) { - if (typeof str !== 'string' || str === '') { - return false; - } - - if (isExtglob(str)) return true; - - var regex = /(\\).|([*?]|\[.*\]|\{.*\}|\(.*\|.*\)|^!)/; - var match; - - while ((match = regex.exec(str))) { - if (match[2]) return true; - str = str.slice(match.index + match[0].length); - } - return false; -}; - - -/***/ }), -/* 725 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var path = __webpack_require__(16); -var inspect = __webpack_require__(29).inspect; - -function assertPath(path) { - if (typeof path !== 'string') { - throw new TypeError('Path must be a string. Received ' + inspect(path)); - } -} - -function posix(path) { - assertPath(path); - if (path.length === 0) - return '.'; - var code = path.charCodeAt(0); - var hasRoot = (code === 47/*/*/); - var end = -1; - var matchedSlash = true; - for (var i = path.length - 1; i >= 1; --i) { - code = path.charCodeAt(i); - if (code === 47/*/*/) { - if (!matchedSlash) { - end = i; - break; - } - } else { - // We saw the first non-path separator - matchedSlash = false; - } - } - - if (end === -1) - return hasRoot ? '/' : '.'; - if (hasRoot && end === 1) - return '//'; - return path.slice(0, end); -} - -function win32(path) { - assertPath(path); - var len = path.length; - if (len === 0) - return '.'; - var rootEnd = -1; - var end = -1; - var matchedSlash = true; - var offset = 0; - var code = path.charCodeAt(0); - - // Try to match a root - if (len > 1) { - if (code === 47/*/*/ || code === 92/*\*/) { - // Possible UNC root - - rootEnd = offset = 1; - - code = path.charCodeAt(1); - if (code === 47/*/*/ || code === 92/*\*/) { - // Matched double path separator at beginning - var j = 2; - var last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - code = path.charCodeAt(j); - if (code === 47/*/*/ || code === 92/*\*/) - break; - } - if (j < len && j !== last) { - // Matched! - last = j; - // Match 1 or more path separators - for (; j < len; ++j) { - code = path.charCodeAt(j); - if (code !== 47/*/*/ && code !== 92/*\*/) - break; - } - if (j < len && j !== last) { - // Matched! - last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - code = path.charCodeAt(j); - if (code === 47/*/*/ || code === 92/*\*/) - break; - } - if (j === len) { - // We matched a UNC root only - return path; - } - if (j !== last) { - // We matched a UNC root with leftovers - - // Offset by 1 to include the separator after the UNC root to - // treat it as a "normal root" on top of a (UNC) root - rootEnd = offset = j + 1; - } - } - } - } - } else if ((code >= 65/*A*/ && code <= 90/*Z*/) || - (code >= 97/*a*/ && code <= 122/*z*/)) { - // Possible device root - - code = path.charCodeAt(1); - if (path.charCodeAt(1) === 58/*:*/) { - rootEnd = offset = 2; - if (len > 2) { - code = path.charCodeAt(2); - if (code === 47/*/*/ || code === 92/*\*/) - rootEnd = offset = 3; - } - } - } - } else if (code === 47/*/*/ || code === 92/*\*/) { - return path[0]; - } - - for (var i = len - 1; i >= offset; --i) { - code = path.charCodeAt(i); - if (code === 47/*/*/ || code === 92/*\*/) { - if (!matchedSlash) { - end = i; - break; - } - } else { - // We saw the first non-path separator - matchedSlash = false; - } - } - - if (end === -1) { - if (rootEnd === -1) - return '.'; - else - end = rootEnd; - } - return path.slice(0, end); -} - -module.exports = process.platform === 'win32' ? win32 : posix; -module.exports.posix = posix; -module.exports.win32 = win32; - - -/***/ }), -/* 726 */ -/***/ (function(module, exports, __webpack_require__) { - -/*! - * is-glob - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - -var isExtglob = __webpack_require__(606); -var chars = { '{': '}', '(': ')', '[': ']'}; - -module.exports = function isGlob(str, options) { - if (typeof str !== 'string' || str === '') { - return false; - } - - if (isExtglob(str)) { - return true; - } - - var regex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; - var match; - - // optionally relax regex - if (options && options.strict === false) { - regex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; - } - - while ((match = regex.exec(str))) { - if (match[2]) return true; - var idx = match.index + match[0].length; - - // if an open bracket/brace/paren is escaped, - // set the index to the next closing character - var open = match[1]; - var close = open ? chars[open] : null; - if (open && close) { - var n = str.indexOf(close, idx); - if (n !== -1) { - idx = n + 1; - } - } - - str = str.slice(idx); - } - return false; -}; - - -/***/ }), -/* 727 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Module dependencies - */ - -var util = __webpack_require__(29); -var braces = __webpack_require__(728); -var toRegex = __webpack_require__(830); -var extend = __webpack_require__(838); - -/** - * Local dependencies - */ - -var compilers = __webpack_require__(841); -var parsers = __webpack_require__(873); -var cache = __webpack_require__(874); -var utils = __webpack_require__(875); -var MAX_LENGTH = 1024 * 64; - -/** - * The main function takes a list of strings and one or more - * glob patterns to use for matching. - * - * ```js - * var mm = require('micromatch'); - * mm(list, patterns[, options]); - * - * console.log(mm(['a.js', 'a.txt'], ['*.js'])); - * //=> [ 'a.js' ] - * ``` - * @param {Array} `list` A list of strings to match - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of matches - * @summary false - * @api public - */ - -function micromatch(list, patterns, options) { - patterns = utils.arrayify(patterns); - list = utils.arrayify(list); - - var len = patterns.length; - if (list.length === 0 || len === 0) { - return []; - } - - if (len === 1) { - return micromatch.match(list, patterns[0], options); - } - - var omit = []; - var keep = []; - var idx = -1; - - while (++idx < len) { - var pattern = patterns[idx]; - - if (typeof pattern === 'string' && pattern.charCodeAt(0) === 33 /* ! */) { - omit.push.apply(omit, micromatch.match(list, pattern.slice(1), options)); - } else { - keep.push.apply(keep, micromatch.match(list, pattern, options)); - } - } - - var matches = utils.diff(keep, omit); - if (!options || options.nodupes !== false) { - return utils.unique(matches); - } - - return matches; -} - -/** - * Similar to the main function, but `pattern` must be a string. - * - * ```js - * var mm = require('micromatch'); - * mm.match(list, pattern[, options]); - * - * console.log(mm.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); - * //=> ['a.a', 'a.aa'] - * ``` - * @param {Array} `list` Array of strings to match - * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of matches - * @api public - */ - -micromatch.match = function(list, pattern, options) { - if (Array.isArray(pattern)) { - throw new TypeError('expected pattern to be a string'); - } - - var unixify = utils.unixify(options); - var isMatch = memoize('match', pattern, options, micromatch.matcher); - var matches = []; - - list = utils.arrayify(list); - var len = list.length; - var idx = -1; - - while (++idx < len) { - var ele = list[idx]; - if (ele === pattern || isMatch(ele)) { - matches.push(utils.value(ele, unixify, options)); - } - } - - // if no options were passed, uniquify results and return - if (typeof options === 'undefined') { - return utils.unique(matches); - } - - if (matches.length === 0) { - if (options.failglob === true) { - throw new Error('no matches found for "' + pattern + '"'); - } - if (options.nonull === true || options.nullglob === true) { - return [options.unescape ? utils.unescape(pattern) : pattern]; - } - } - - // if `opts.ignore` was defined, diff ignored list - if (options.ignore) { - matches = micromatch.not(matches, options.ignore, options); - } - - return options.nodupes !== false ? utils.unique(matches) : matches; -}; - -/** - * Returns true if the specified `string` matches the given glob `pattern`. - * - * ```js - * var mm = require('micromatch'); - * mm.isMatch(string, pattern[, options]); - * - * console.log(mm.isMatch('a.a', '*.a')); - * //=> true - * console.log(mm.isMatch('a.b', '*.a')); - * //=> false - * ``` - * @param {String} `string` String to match - * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if the string matches the glob pattern. - * @api public - */ - -micromatch.isMatch = function(str, pattern, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (isEmptyString(str) || isEmptyString(pattern)) { - return false; - } - - var equals = utils.equalsPattern(options); - if (equals(str)) { - return true; - } - - var isMatch = memoize('isMatch', pattern, options, micromatch.matcher); - return isMatch(str); -}; - -/** - * Returns true if some of the strings in the given `list` match any of the - * given glob `patterns`. - * - * ```js - * var mm = require('micromatch'); - * mm.some(list, patterns[, options]); - * - * console.log(mm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); - * // true - * console.log(mm.some(['foo.js'], ['*.js', '!foo.js'])); - * // false - * ``` - * @param {String|Array} `list` The string or array of strings to test. Returns as soon as the first match is found. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -micromatch.some = function(list, patterns, options) { - if (typeof list === 'string') { - list = [list]; - } - for (var i = 0; i < list.length; i++) { - if (micromatch(list[i], patterns, options).length === 1) { - return true; - } - } - return false; -}; - -/** - * Returns true if every string in the given `list` matches - * any of the given glob `patterns`. - * - * ```js - * var mm = require('micromatch'); - * mm.every(list, patterns[, options]); - * - * console.log(mm.every('foo.js', ['foo.js'])); - * // true - * console.log(mm.every(['foo.js', 'bar.js'], ['*.js'])); - * // true - * console.log(mm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); - * // false - * console.log(mm.every(['foo.js'], ['*.js', '!foo.js'])); - * // false - * ``` - * @param {String|Array} `list` The string or array of strings to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -micromatch.every = function(list, patterns, options) { - if (typeof list === 'string') { - list = [list]; - } - for (var i = 0; i < list.length; i++) { - if (micromatch(list[i], patterns, options).length !== 1) { - return false; - } - } - return true; -}; - -/** - * Returns true if **any** of the given glob `patterns` - * match the specified `string`. - * - * ```js - * var mm = require('micromatch'); - * mm.any(string, patterns[, options]); - * - * console.log(mm.any('a.a', ['b.*', '*.a'])); - * //=> true - * console.log(mm.any('a.a', 'b.*')); - * //=> false - * ``` - * @param {String|Array} `str` The string to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -micromatch.any = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (isEmptyString(str) || isEmptyString(patterns)) { - return false; - } - - if (typeof patterns === 'string') { - patterns = [patterns]; - } - - for (var i = 0; i < patterns.length; i++) { - if (micromatch.isMatch(str, patterns[i], options)) { - return true; - } - } - return false; -}; - -/** - * Returns true if **all** of the given `patterns` match - * the specified string. - * - * ```js - * var mm = require('micromatch'); - * mm.all(string, patterns[, options]); - * - * console.log(mm.all('foo.js', ['foo.js'])); - * // true - * - * console.log(mm.all('foo.js', ['*.js', '!foo.js'])); - * // false - * - * console.log(mm.all('foo.js', ['*.js', 'foo.js'])); - * // true - * - * console.log(mm.all('foo.js', ['*.js', 'f*', '*o*', '*o.js'])); - * // true - * ``` - * @param {String|Array} `str` The string to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -micromatch.all = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - if (typeof patterns === 'string') { - patterns = [patterns]; - } - for (var i = 0; i < patterns.length; i++) { - if (!micromatch.isMatch(str, patterns[i], options)) { - return false; - } - } - return true; -}; - -/** - * Returns a list of strings that _**do not match any**_ of the given `patterns`. - * - * ```js - * var mm = require('micromatch'); - * mm.not(list, patterns[, options]); - * - * console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); - * //=> ['b.b', 'c.c'] - * ``` - * @param {Array} `list` Array of strings to match. - * @param {String|Array} `patterns` One or more glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of strings that **do not match** the given patterns. - * @api public - */ - -micromatch.not = function(list, patterns, options) { - var opts = extend({}, options); - var ignore = opts.ignore; - delete opts.ignore; - - var unixify = utils.unixify(opts); - list = utils.arrayify(list).map(unixify); - - var matches = utils.diff(list, micromatch(list, patterns, opts)); - if (ignore) { - matches = utils.diff(matches, micromatch(list, ignore)); - } - - return opts.nodupes !== false ? utils.unique(matches) : matches; -}; - -/** - * Returns true if the given `string` contains the given pattern. Similar - * to [.isMatch](#isMatch) but the pattern can match any part of the string. - * - * ```js - * var mm = require('micromatch'); - * mm.contains(string, pattern[, options]); - * - * console.log(mm.contains('aa/bb/cc', '*b')); - * //=> true - * console.log(mm.contains('aa/bb/cc', '*d')); - * //=> false - * ``` - * @param {String} `str` The string to match. - * @param {String|Array} `patterns` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if the patter matches any part of `str`. - * @api public - */ - -micromatch.contains = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (typeof patterns === 'string') { - if (isEmptyString(str) || isEmptyString(patterns)) { - return false; - } - - var equals = utils.equalsPattern(patterns, options); - if (equals(str)) { - return true; - } - var contains = utils.containsPattern(patterns, options); - if (contains(str)) { - return true; - } - } - - var opts = extend({}, options, {contains: true}); - return micromatch.any(str, patterns, opts); -}; - -/** - * Returns true if the given pattern and options should enable - * the `matchBase` option. - * @return {Boolean} - * @api private - */ - -micromatch.matchBase = function(pattern, options) { - if (pattern && pattern.indexOf('/') !== -1 || !options) return false; - return options.basename === true || options.matchBase === true; -}; - -/** - * Filter the keys of the given object with the given `glob` pattern - * and `options`. Does not attempt to match nested keys. If you need this feature, - * use [glob-object][] instead. - * - * ```js - * var mm = require('micromatch'); - * mm.matchKeys(object, patterns[, options]); - * - * var obj = { aa: 'a', ab: 'b', ac: 'c' }; - * console.log(mm.matchKeys(obj, '*b')); - * //=> { ab: 'b' } - * ``` - * @param {Object} `object` The object with keys to filter. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Object} Returns an object with only keys that match the given patterns. - * @api public - */ - -micromatch.matchKeys = function(obj, patterns, options) { - if (!utils.isObject(obj)) { - throw new TypeError('expected the first argument to be an object'); - } - var keys = micromatch(Object.keys(obj), patterns, options); - return utils.pick(obj, keys); -}; - -/** - * Returns a memoized matcher function from the given glob `pattern` and `options`. - * The returned function takes a string to match as its only argument and returns - * true if the string is a match. - * - * ```js - * var mm = require('micromatch'); - * mm.matcher(pattern[, options]); - * - * var isMatch = mm.matcher('*.!(*a)'); - * console.log(isMatch('a.a')); - * //=> false - * console.log(isMatch('a.b')); - * //=> true - * ``` - * @param {String} `pattern` Glob pattern - * @param {Object} `options` See available [options](#options) for changing how matches are performed. - * @return {Function} Returns a matcher function. - * @api public - */ - -micromatch.matcher = function matcher(pattern, options) { - if (Array.isArray(pattern)) { - return compose(pattern, options, matcher); - } - - // if pattern is a regex - if (pattern instanceof RegExp) { - return test(pattern); - } - - // if pattern is invalid - if (!utils.isString(pattern)) { - throw new TypeError('expected pattern to be an array, string or regex'); - } - - // if pattern is a non-glob string - if (!utils.hasSpecialChars(pattern)) { - if (options && options.nocase === true) { - pattern = pattern.toLowerCase(); - } - return utils.matchPath(pattern, options); - } - - // if pattern is a glob string - var re = micromatch.makeRe(pattern, options); - - // if `options.matchBase` or `options.basename` is defined - if (micromatch.matchBase(pattern, options)) { - return utils.matchBasename(re, options); - } - - function test(regex) { - var equals = utils.equalsPattern(options); - var unixify = utils.unixify(options); - - return function(str) { - if (equals(str)) { - return true; - } - - if (regex.test(unixify(str))) { - return true; - } - return false; - }; - } - - var fn = test(re); - Object.defineProperty(fn, 'result', { - configurable: true, - enumerable: false, - value: re.result - }); - return fn; -}; - -/** - * Returns an array of matches captured by `pattern` in `string, or `null` if the pattern did not match. - * - * ```js - * var mm = require('micromatch'); - * mm.capture(pattern, string[, options]); - * - * console.log(mm.capture('test/*.js', 'test/foo.js')); - * //=> ['foo'] - * console.log(mm.capture('test/*.js', 'foo/bar.css')); - * //=> null - * ``` - * @param {String} `pattern` Glob pattern to use for matching. - * @param {String} `string` String to match - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns an array of captures if the string matches the glob pattern, otherwise `null`. - * @api public - */ - -micromatch.capture = function(pattern, str, options) { - var re = micromatch.makeRe(pattern, extend({capture: true}, options)); - var unixify = utils.unixify(options); - - function match() { - return function(string) { - var match = re.exec(unixify(string)); - if (!match) { - return null; - } - - return match.slice(1); - }; - } - - var capture = memoize('capture', pattern, options, match); - return capture(str); -}; - -/** - * Create a regular expression from the given glob `pattern`. - * - * ```js - * var mm = require('micromatch'); - * mm.makeRe(pattern[, options]); - * - * console.log(mm.makeRe('*.js')); - * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ - * ``` - * @param {String} `pattern` A glob pattern to convert to regex. - * @param {Object} `options` See available [options](#options) for changing how matches are performed. - * @return {RegExp} Returns a regex created from the given pattern. - * @api public - */ - -micromatch.makeRe = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - if (pattern.length > MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); - } - - function makeRe() { - var result = micromatch.create(pattern, options); - var ast_array = []; - var output = result.map(function(obj) { - obj.ast.state = obj.state; - ast_array.push(obj.ast); - return obj.output; - }); - - var regex = toRegex(output.join('|'), options); - Object.defineProperty(regex, 'result', { - configurable: true, - enumerable: false, - value: ast_array - }); - return regex; - } - - return memoize('makeRe', pattern, options, makeRe); -}; - -/** - * Expand the given brace `pattern`. - * - * ```js - * var mm = require('micromatch'); - * console.log(mm.braces('foo/{a,b}/bar')); - * //=> ['foo/(a|b)/bar'] - * - * console.log(mm.braces('foo/{a,b}/bar', {expand: true})); - * //=> ['foo/(a|b)/bar'] - * ``` - * @param {String} `pattern` String with brace pattern to expand. - * @param {Object} `options` Any [options](#options) to change how expansion is performed. See the [braces][] library for all available options. - * @return {Array} - * @api public - */ - -micromatch.braces = function(pattern, options) { - if (typeof pattern !== 'string' && !Array.isArray(pattern)) { - throw new TypeError('expected pattern to be an array or string'); - } - - function expand() { - if (options && options.nobrace === true || !/\{.*\}/.test(pattern)) { - return utils.arrayify(pattern); - } - return braces(pattern, options); - } - - return memoize('braces', pattern, options, expand); -}; - -/** - * Proxy to the [micromatch.braces](#method), for parity with - * minimatch. - */ - -micromatch.braceExpand = function(pattern, options) { - var opts = extend({}, options, {expand: true}); - return micromatch.braces(pattern, opts); -}; - -/** - * Parses the given glob `pattern` and returns an array of abstract syntax - * trees (ASTs), with the compiled `output` and optional source `map` on - * each AST. - * - * ```js - * var mm = require('micromatch'); - * mm.create(pattern[, options]); - * - * console.log(mm.create('abc/*.js')); - * // [{ options: { source: 'string', sourcemap: true }, - * // state: {}, - * // compilers: - * // { ... }, - * // output: '(\\.[\\\\\\/])?abc\\/(?!\\.)(?=.)[^\\/]*?\\.js', - * // ast: - * // { type: 'root', - * // errors: [], - * // nodes: - * // [ ... ], - * // dot: false, - * // input: 'abc/*.js' }, - * // parsingErrors: [], - * // map: - * // { version: 3, - * // sources: [ 'string' ], - * // names: [], - * // mappings: 'AAAA,GAAG,EAAC,kBAAC,EAAC,EAAE', - * // sourcesContent: [ 'abc/*.js' ] }, - * // position: { line: 1, column: 28 }, - * // content: {}, - * // files: {}, - * // idx: 6 }] - * ``` - * @param {String} `pattern` Glob pattern to parse and compile. - * @param {Object} `options` Any [options](#options) to change how parsing and compiling is performed. - * @return {Object} Returns an object with the parsed AST, compiled string and optional source map. - * @api public - */ - -micromatch.create = function(pattern, options) { - return memoize('create', pattern, options, function() { - function create(str, opts) { - return micromatch.compile(micromatch.parse(str, opts), opts); - } - - pattern = micromatch.braces(pattern, options); - var len = pattern.length; - var idx = -1; - var res = []; - - while (++idx < len) { - res.push(create(pattern[idx], options)); - } - return res; - }); -}; - -/** - * Parse the given `str` with the given `options`. - * - * ```js - * var mm = require('micromatch'); - * mm.parse(pattern[, options]); - * - * var ast = mm.parse('a/{b,c}/d'); - * console.log(ast); - * // { type: 'root', - * // errors: [], - * // input: 'a/{b,c}/d', - * // nodes: - * // [ { type: 'bos', val: '' }, - * // { type: 'text', val: 'a/' }, - * // { type: 'brace', - * // nodes: - * // [ { type: 'brace.open', val: '{' }, - * // { type: 'text', val: 'b,c' }, - * // { type: 'brace.close', val: '}' } ] }, - * // { type: 'text', val: '/d' }, - * // { type: 'eos', val: '' } ] } - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {Object} Returns an AST - * @api public - */ - -micromatch.parse = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - function parse() { - var snapdragon = utils.instantiate(null, options); - parsers(snapdragon, options); - - var ast = snapdragon.parse(pattern, options); - utils.define(ast, 'snapdragon', snapdragon); - ast.input = pattern; - return ast; - } - - return memoize('parse', pattern, options, parse); -}; - -/** - * Compile the given `ast` or string with the given `options`. - * - * ```js - * var mm = require('micromatch'); - * mm.compile(ast[, options]); - * - * var ast = mm.parse('a/{b,c}/d'); - * console.log(mm.compile(ast)); - * // { options: { source: 'string' }, - * // state: {}, - * // compilers: - * // { eos: [Function], - * // noop: [Function], - * // bos: [Function], - * // brace: [Function], - * // 'brace.open': [Function], - * // text: [Function], - * // 'brace.close': [Function] }, - * // output: [ 'a/(b|c)/d' ], - * // ast: - * // { ... }, - * // parsingErrors: [] } - * ``` - * @param {Object|String} `ast` - * @param {Object} `options` - * @return {Object} Returns an object that has an `output` property with the compiled string. - * @api public - */ - -micromatch.compile = function(ast, options) { - if (typeof ast === 'string') { - ast = micromatch.parse(ast, options); - } - - return memoize('compile', ast.input, options, function() { - var snapdragon = utils.instantiate(ast, options); - compilers(snapdragon, options); - return snapdragon.compile(ast, options); - }); -}; - -/** - * Clear the regex cache. - * - * ```js - * mm.clearCache(); - * ``` - * @api public - */ - -micromatch.clearCache = function() { - micromatch.cache.caches = {}; -}; - -/** - * Returns true if the given value is effectively an empty string - */ - -function isEmptyString(val) { - return String(val) === '' || String(val) === './'; -} - -/** - * Compose a matcher function with the given patterns. - * This allows matcher functions to be compiled once and - * called multiple times. - */ - -function compose(patterns, options, matcher) { - var matchers; - - return memoize('compose', String(patterns), options, function() { - return function(file) { - // delay composition until it's invoked the first time, - // after that it won't be called again - if (!matchers) { - matchers = []; - for (var i = 0; i < patterns.length; i++) { - matchers.push(matcher(patterns[i], options)); - } - } - - var len = matchers.length; - while (len--) { - if (matchers[len](file) === true) { - return true; - } - } - return false; - }; - }); -} - -/** - * Memoize a generated regex or function. A unique key is generated - * from the `type` (usually method name), the `pattern`, and - * user-defined options. - */ - -function memoize(type, pattern, options, fn) { - var key = utils.createKey(type + '=' + pattern, options); - - if (options && options.cache === false) { - return fn(pattern, options); - } - - if (cache.has(type, key)) { - return cache.get(type, key); - } - - var val = fn(pattern, options); - cache.set(type, key, val); - return val; -} - -/** - * Expose compiler, parser and cache on `micromatch` - */ - -micromatch.compilers = compilers; -micromatch.parsers = parsers; -micromatch.caches = cache.caches; - -/** - * Expose `micromatch` - * @type {Function} - */ - -module.exports = micromatch; - - -/***/ }), -/* 728 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Module dependencies - */ - -var toRegex = __webpack_require__(729); -var unique = __webpack_require__(741); -var extend = __webpack_require__(738); - -/** - * Local dependencies - */ - -var compilers = __webpack_require__(742); -var parsers = __webpack_require__(757); -var Braces = __webpack_require__(767); -var utils = __webpack_require__(743); -var MAX_LENGTH = 1024 * 64; -var cache = {}; - -/** - * Convert the given `braces` pattern into a regex-compatible string. By default, only one string is generated for every input string. Set `options.expand` to true to return an array of patterns (similar to Bash or minimatch. Before using `options.expand`, it's recommended that you read the [performance notes](#performance)). - * - * ```js - * var braces = require('braces'); - * console.log(braces('{a,b,c}')); - * //=> ['(a|b|c)'] - * - * console.log(braces('{a,b,c}', {expand: true})); - * //=> ['a', 'b', 'c'] - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {String} - * @api public - */ - -function braces(pattern, options) { - var key = utils.createKey(String(pattern), options); - var arr = []; - - var disabled = options && options.cache === false; - if (!disabled && cache.hasOwnProperty(key)) { - return cache[key]; - } - - if (Array.isArray(pattern)) { - for (var i = 0; i < pattern.length; i++) { - arr.push.apply(arr, braces.create(pattern[i], options)); - } - } else { - arr = braces.create(pattern, options); - } - - if (options && options.nodupes === true) { - arr = unique(arr); - } - - if (!disabled) { - cache[key] = arr; - } - return arr; -} - -/** - * Expands a brace pattern into an array. This method is called by the main [braces](#braces) function when `options.expand` is true. Before using this method it's recommended that you read the [performance notes](#performance)) and advantages of using [.optimize](#optimize) instead. - * - * ```js - * var braces = require('braces'); - * console.log(braces.expand('a/{b,c}/d')); - * //=> ['a/b/d', 'a/c/d']; - * ``` - * @param {String} `pattern` Brace pattern - * @param {Object} `options` - * @return {Array} Returns an array of expanded values. - * @api public - */ - -braces.expand = function(pattern, options) { - return braces.create(pattern, extend({}, options, {expand: true})); -}; - -/** - * Expands a brace pattern into a regex-compatible, optimized string. This method is called by the main [braces](#braces) function by default. - * - * ```js - * var braces = require('braces'); - * console.log(braces.expand('a/{b,c}/d')); - * //=> ['a/(b|c)/d'] - * ``` - * @param {String} `pattern` Brace pattern - * @param {Object} `options` - * @return {Array} Returns an array of expanded values. - * @api public - */ - -braces.optimize = function(pattern, options) { - return braces.create(pattern, options); -}; - -/** - * Processes a brace pattern and returns either an expanded array (if `options.expand` is true), a highly optimized regex-compatible string. This method is called by the main [braces](#braces) function. - * - * ```js - * var braces = require('braces'); - * console.log(braces.create('user-{200..300}/project-{a,b,c}-{1..10}')) - * //=> 'user-(20[0-9]|2[1-9][0-9]|300)/project-(a|b|c)-([1-9]|10)' - * ``` - * @param {String} `pattern` Brace pattern - * @param {Object} `options` - * @return {Array} Returns an array of expanded values. - * @api public - */ - -braces.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - var maxLength = (options && options.maxLength) || MAX_LENGTH; - if (pattern.length >= maxLength) { - throw new Error('expected pattern to be less than ' + maxLength + ' characters'); - } - - function create() { - if (pattern === '' || pattern.length < 3) { - return [pattern]; - } - - if (utils.isEmptySets(pattern)) { - return []; - } - - if (utils.isQuotedString(pattern)) { - return [pattern.slice(1, -1)]; - } - - var proto = new Braces(options); - var result = !options || options.expand !== true - ? proto.optimize(pattern, options) - : proto.expand(pattern, options); - - // get the generated pattern(s) - var arr = result.output; - - // filter out empty strings if specified - if (options && options.noempty === true) { - arr = arr.filter(Boolean); - } - - // filter out duplicates if specified - if (options && options.nodupes === true) { - arr = unique(arr); - } - - Object.defineProperty(arr, 'result', { - enumerable: false, - value: result - }); - - return arr; - } - - return memoize('create', pattern, options, create); -}; - -/** - * Create a regular expression from the given string `pattern`. - * - * ```js - * var braces = require('braces'); - * - * console.log(braces.makeRe('id-{200..300}')); - * //=> /^(?:id-(20[0-9]|2[1-9][0-9]|300))$/ - * ``` - * @param {String} `pattern` The pattern to convert to regex. - * @param {Object} `options` - * @return {RegExp} - * @api public - */ - -braces.makeRe = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - var maxLength = (options && options.maxLength) || MAX_LENGTH; - if (pattern.length >= maxLength) { - throw new Error('expected pattern to be less than ' + maxLength + ' characters'); - } - - function makeRe() { - var arr = braces(pattern, options); - var opts = extend({strictErrors: false}, options); - return toRegex(arr, opts); - } - - return memoize('makeRe', pattern, options, makeRe); -}; - -/** - * Parse the given `str` with the given `options`. - * - * ```js - * var braces = require('braces'); - * var ast = braces.parse('a/{b,c}/d'); - * console.log(ast); - * // { type: 'root', - * // errors: [], - * // input: 'a/{b,c}/d', - * // nodes: - * // [ { type: 'bos', val: '' }, - * // { type: 'text', val: 'a/' }, - * // { type: 'brace', - * // nodes: - * // [ { type: 'brace.open', val: '{' }, - * // { type: 'text', val: 'b,c' }, - * // { type: 'brace.close', val: '}' } ] }, - * // { type: 'text', val: '/d' }, - * // { type: 'eos', val: '' } ] } - * ``` - * @param {String} `pattern` Brace pattern to parse - * @param {Object} `options` - * @return {Object} Returns an AST - * @api public - */ - -braces.parse = function(pattern, options) { - var proto = new Braces(options); - return proto.parse(pattern, options); -}; - -/** - * Compile the given `ast` or string with the given `options`. - * - * ```js - * var braces = require('braces'); - * var ast = braces.parse('a/{b,c}/d'); - * console.log(braces.compile(ast)); - * // { options: { source: 'string' }, - * // state: {}, - * // compilers: - * // { eos: [Function], - * // noop: [Function], - * // bos: [Function], - * // brace: [Function], - * // 'brace.open': [Function], - * // text: [Function], - * // 'brace.close': [Function] }, - * // output: [ 'a/(b|c)/d' ], - * // ast: - * // { ... }, - * // parsingErrors: [] } - * ``` - * @param {Object|String} `ast` AST from [.parse](#parse). If a string is passed it will be parsed first. - * @param {Object} `options` - * @return {Object} Returns an object that has an `output` property with the compiled string. - * @api public - */ - -braces.compile = function(ast, options) { - var proto = new Braces(options); - return proto.compile(ast, options); -}; - -/** - * Clear the regex cache. - * - * ```js - * braces.clearCache(); - * ``` - * @api public - */ - -braces.clearCache = function() { - cache = braces.cache = {}; -}; - -/** - * Memoize a generated regex or function. A unique key is generated - * from the method name, pattern, and user-defined options. Set - * options.memoize to false to disable. - */ - -function memoize(type, pattern, options, fn) { - var key = utils.createKey(type + ':' + pattern, options); - var disabled = options && options.cache === false; - if (disabled) { - braces.clearCache(); - return fn(pattern, options); - } - - if (cache.hasOwnProperty(key)) { - return cache[key]; - } - - var res = fn(pattern, options); - cache[key] = res; - return res; -} - -/** - * Expose `Braces` constructor and methods - * @type {Function} - */ - -braces.Braces = Braces; -braces.compilers = compilers; -braces.parsers = parsers; -braces.cache = cache; - -/** - * Expose `braces` - * @type {Function} - */ - -module.exports = braces; - - -/***/ }), -/* 729 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var define = __webpack_require__(730); -var extend = __webpack_require__(738); -var not = __webpack_require__(740); -var MAX_LENGTH = 1024 * 64; - -/** - * Session cache - */ - -var cache = {}; - -/** - * Create a regular expression from the given `pattern` string. - * - * @param {String|RegExp} `pattern` Pattern can be a string or regular expression. - * @param {Object} `options` - * @return {RegExp} - * @api public - */ - -module.exports = function(patterns, options) { - if (!Array.isArray(patterns)) { - return makeRe(patterns, options); - } - return makeRe(patterns.join('|'), options); -}; - -/** - * Create a regular expression from the given `pattern` string. - * - * @param {String|RegExp} `pattern` Pattern can be a string or regular expression. - * @param {Object} `options` - * @return {RegExp} - * @api public - */ - -function makeRe(pattern, options) { - if (pattern instanceof RegExp) { - return pattern; - } - - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - if (pattern.length > MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); - } - - var key = pattern; - // do this before shallow cloning options, it's a lot faster - if (!options || (options && options.cache !== false)) { - key = createKey(pattern, options); - - if (cache.hasOwnProperty(key)) { - return cache[key]; - } - } - - var opts = extend({}, options); - if (opts.contains === true) { - if (opts.negate === true) { - opts.strictNegate = false; - } else { - opts.strict = false; - } - } - - if (opts.strict === false) { - opts.strictOpen = false; - opts.strictClose = false; - } - - var open = opts.strictOpen !== false ? '^' : ''; - var close = opts.strictClose !== false ? '$' : ''; - var flags = opts.flags || ''; - var regex; - - if (opts.nocase === true && !/i/.test(flags)) { - flags += 'i'; - } - - try { - if (opts.negate || typeof opts.strictNegate === 'boolean') { - pattern = not.create(pattern, opts); - } - var str = open + '(?:' + pattern + ')' + close; - regex = new RegExp(str, flags); - } catch (err) { - if (opts.strictErrors === true) { - err.key = key; - err.pattern = pattern; - err.originalOptions = options; - err.createdOptions = opts; - throw err; - } - - try { - regex = new RegExp('^' + pattern.replace(/(\W)/g, '\\$1') + '$'); - } catch (err) { - regex = /.^/; //<= match nothing - } - } - - if (opts.cache !== false) { - cacheRegex(regex, key, pattern, opts); - } - return regex; -} - -/** - * Cache generated regex. This can result in dramatic speed improvements - * and simplify debugging by adding options and pattern to the regex. It can be - * disabled by passing setting `options.cache` to false. - */ - -function cacheRegex(regex, key, pattern, options) { - define(regex, 'cached', true); - define(regex, 'pattern', pattern); - define(regex, 'options', options); - define(regex, 'key', key); - cache[key] = regex; -} - -/** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ - -function createKey(pattern, options) { - if (!options) return pattern; - var key = pattern; - for (var prop in options) { - if (options.hasOwnProperty(prop)) { - key += ';' + prop + '=' + String(options[prop]); - } - } - return key; -} - -/** - * Expose `makeRe` - */ - -module.exports.makeRe = makeRe; - - -/***/ }), -/* 730 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var isDescriptor = __webpack_require__(731); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } - - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; - - -/***/ }), -/* 731 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var typeOf = __webpack_require__(732); -var isAccessor = __webpack_require__(733); -var isData = __webpack_require__(736); - -module.exports = function isDescriptor(obj, key) { - if (typeOf(obj) !== 'object') { - return false; - } - if ('get' in obj) { - return isAccessor(obj, key); - } - return isData(obj, key); -}; - - -/***/ }), -/* 732 */ -/***/ (function(module, exports) { - -var toString = Object.prototype.toString; - -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ - -module.exports = function kindOf(val) { - var type = typeof val; - - // primitivies - if (type === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (type === 'string' || val instanceof String) { - return 'string'; - } - if (type === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (type === 'function' || val instanceof Function) { - if (typeof val.constructor.name !== 'undefined' && val.constructor.name.slice(0, 9) === 'Generator') { - return 'generatorfunction'; - } - return 'function'; - } - - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } - - // other objects - type = toString.call(val); - - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - if (type === '[object Promise]') { - return 'promise'; - } - - // buffer - if (isBuffer(val)) { - return 'buffer'; - } - - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - - if (type === '[object Map Iterator]') { - return 'mapiterator'; - } - if (type === '[object Set Iterator]') { - return 'setiterator'; - } - if (type === '[object String Iterator]') { - return 'stringiterator'; - } - if (type === '[object Array Iterator]') { - return 'arrayiterator'; - } - - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } - - // must be a plain object - return 'object'; -}; - -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ - -function isBuffer(val) { - return val.constructor - && typeof val.constructor.isBuffer === 'function' - && val.constructor.isBuffer(val); -} - - -/***/ }), -/* 733 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-accessor-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var typeOf = __webpack_require__(734); - -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' -}; - -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } - - if (typeOf(obj) !== 'object') { - return false; - } - - if (has(obj, 'value') || has(obj, 'writable')) { - return false; - } - - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; - } - - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; - } - - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { - continue; - } - - if (typeOf(obj[key]) === accessor[key]) { - continue; - } - - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -} - -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); -} - -/** - * Expose `isAccessorDescriptor` - */ - -module.exports = isAccessorDescriptor; - - -/***/ }), -/* 734 */ -/***/ (function(module, exports, __webpack_require__) { - -var isBuffer = __webpack_require__(735); -var toString = Object.prototype.toString; - -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ - -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } - - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } - - // other objects - var type = toString.call(val); - - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - - // buffer - if (isBuffer(val)) { - return 'buffer'; - } - - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } - - // must be a plain object - return 'object'; -}; - - -/***/ }), -/* 735 */ -/***/ (function(module, exports) { - -/*! - * Determine if an object is a Buffer - * - * @author Feross Aboukhadijeh - * @license MIT - */ - -// The _isBuffer check is for Safari 5-7 support, because it's missing -// Object.prototype.constructor. Remove this eventually -module.exports = function (obj) { - return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) -} - -function isBuffer (obj) { - return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) -} - -// For Node v0.10 support. Remove this eventually. -function isSlowBuffer (obj) { - return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) -} - - -/***/ }), -/* 736 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-data-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var typeOf = __webpack_require__(737); - -// data descriptor properties -var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' -}; - -function isDataDescriptor(obj, prop) { - if (typeOf(obj) !== 'object') { - return false; - } - - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } - - if (!('value' in obj) && !('writable' in obj)) { - return false; - } - - for (var key in obj) { - if (key === 'value') continue; - - if (!data.hasOwnProperty(key)) { - continue; - } - - if (typeOf(obj[key]) === data[key]) { - continue; - } - - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -} - -/** - * Expose `isDataDescriptor` - */ - -module.exports = isDataDescriptor; - - -/***/ }), -/* 737 */ -/***/ (function(module, exports, __webpack_require__) { - -var isBuffer = __webpack_require__(735); -var toString = Object.prototype.toString; - -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ - -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } - - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } - - // other objects - var type = toString.call(val); - - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - - // buffer - if (isBuffer(val)) { - return 'buffer'; - } - - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } - - // must be a plain object - return 'object'; -}; - - -/***/ }), -/* 738 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(739); - -module.exports = function extend(o/*, objects*/) { - if (!isObject(o)) { o = {}; } - - var len = arguments.length; - for (var i = 1; i < len; i++) { - var obj = arguments[i]; - - if (isObject(obj)) { - assign(o, obj); - } - } - return o; -}; - -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } - } -} - -/** - * Returns true if the given `key` is an own property of `obj`. - */ - -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - - -/***/ }), -/* 739 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -module.exports = function isExtendable(val) { - return typeof val !== 'undefined' && val !== null - && (typeof val === 'object' || typeof val === 'function'); -}; - - -/***/ }), -/* 740 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var extend = __webpack_require__(738); - -/** - * The main export is a function that takes a `pattern` string and an `options` object. - * - * ```js - & var not = require('regex-not'); - & console.log(not('foo')); - & //=> /^(?:(?!^(?:foo)$).)*$/ - * ``` - * - * @param {String} `pattern` - * @param {Object} `options` - * @return {RegExp} Converts the given `pattern` to a regex using the specified `options`. - * @api public - */ - -function toRegex(pattern, options) { - return new RegExp(toRegex.create(pattern, options)); -} - -/** - * Create a regex-compatible string from the given `pattern` and `options`. - * - * ```js - & var not = require('regex-not'); - & console.log(not.create('foo')); - & //=> '^(?:(?!^(?:foo)$).)*$' - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {String} - * @api public - */ - -toRegex.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - var opts = extend({}, options); - if (opts && opts.contains === true) { - opts.strictNegate = false; - } - - var open = opts.strictOpen !== false ? '^' : ''; - var close = opts.strictClose !== false ? '$' : ''; - var endChar = opts.endChar ? opts.endChar : '+'; - var str = pattern; - - if (opts && opts.strictNegate === false) { - str = '(?:(?!(?:' + pattern + ')).)' + endChar; - } else { - str = '(?:(?!^(?:' + pattern + ')$).)' + endChar; - } - - return open + str + close; -}; - -/** - * Expose `toRegex` - */ - -module.exports = toRegex; - - -/***/ }), -/* 741 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * array-unique - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -module.exports = function unique(arr) { - if (!Array.isArray(arr)) { - throw new TypeError('array-unique expects an array.'); - } - - var len = arr.length; - var i = -1; - - while (i++ < len) { - var j = i + 1; - - for (; j < arr.length; ++j) { - if (arr[i] === arr[j]) { - arr.splice(j--, 1); - } - } - } - return arr; -}; - -module.exports.immutable = function uniqueImmutable(arr) { - if (!Array.isArray(arr)) { - throw new TypeError('array-unique expects an array.'); - } - - var arrLen = arr.length; - var newArr = new Array(arrLen); - - for (var i = 0; i < arrLen; i++) { - newArr[i] = arr[i]; - } - - return module.exports(newArr); -}; - - -/***/ }), -/* 742 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = __webpack_require__(743); - -module.exports = function(braces, options) { - braces.compiler - - /** - * bos - */ - - .set('bos', function() { - if (this.output) return; - this.ast.queue = isEscaped(this.ast) ? [this.ast.val] : []; - this.ast.count = 1; - }) - - /** - * Square brackets - */ - - .set('bracket', function(node) { - var close = node.close; - var open = !node.escaped ? '[' : '\\['; - var negated = node.negated; - var inner = node.inner; - - inner = inner.replace(/\\(?=[\\\w]|$)/g, '\\\\'); - if (inner === ']-') { - inner = '\\]\\-'; - } - - if (negated && inner.indexOf('.') === -1) { - inner += '.'; - } - if (negated && inner.indexOf('/') === -1) { - inner += '/'; - } - - var val = open + negated + inner + close; - var queue = node.parent.queue; - var last = utils.arrayify(queue.pop()); - - queue.push(utils.join(last, val)); - queue.push.apply(queue, []); - }) - - /** - * Brace - */ - - .set('brace', function(node) { - node.queue = isEscaped(node) ? [node.val] : []; - node.count = 1; - return this.mapVisit(node.nodes); - }) - - /** - * Open - */ - - .set('brace.open', function(node) { - node.parent.open = node.val; - }) - - /** - * Inner - */ - - .set('text', function(node) { - var queue = node.parent.queue; - var escaped = node.escaped; - var segs = [node.val]; - - if (node.optimize === false) { - options = utils.extend({}, options, {optimize: false}); - } - - if (node.multiplier > 1) { - node.parent.count *= node.multiplier; - } - - if (options.quantifiers === true && utils.isQuantifier(node.val)) { - escaped = true; - - } else if (node.val.length > 1) { - if (isType(node.parent, 'brace') && !isEscaped(node)) { - var expanded = utils.expand(node.val, options); - segs = expanded.segs; - - if (expanded.isOptimized) { - node.parent.isOptimized = true; - } - - // if nothing was expanded, we probably have a literal brace - if (!segs.length) { - var val = (expanded.val || node.val); - if (options.unescape !== false) { - // unescape unexpanded brace sequence/set separators - val = val.replace(/\\([,.])/g, '$1'); - // strip quotes - val = val.replace(/["'`]/g, ''); - } - - segs = [val]; - escaped = true; - } - } - - } else if (node.val === ',') { - if (options.expand) { - node.parent.queue.push(['']); - segs = ['']; - } else { - segs = ['|']; - } - } else { - escaped = true; - } - - if (escaped && isType(node.parent, 'brace')) { - if (node.parent.nodes.length <= 4 && node.parent.count === 1) { - node.parent.escaped = true; - } else if (node.parent.length <= 3) { - node.parent.escaped = true; - } - } - - if (!hasQueue(node.parent)) { - node.parent.queue = segs; - return; - } - - var last = utils.arrayify(queue.pop()); - if (node.parent.count > 1 && options.expand) { - last = multiply(last, node.parent.count); - node.parent.count = 1; - } - - queue.push(utils.join(utils.flatten(last), segs.shift())); - queue.push.apply(queue, segs); - }) - - /** - * Close - */ - - .set('brace.close', function(node) { - var queue = node.parent.queue; - var prev = node.parent.parent; - var last = prev.queue.pop(); - var open = node.parent.open; - var close = node.val; - - if (open && close && isOptimized(node, options)) { - open = '('; - close = ')'; - } - - // if a close brace exists, and the previous segment is one character - // don't wrap the result in braces or parens - var ele = utils.last(queue); - if (node.parent.count > 1 && options.expand) { - ele = multiply(queue.pop(), node.parent.count); - node.parent.count = 1; - queue.push(ele); - } - - if (close && typeof ele === 'string' && ele.length === 1) { - open = ''; - close = ''; - } - - if ((isLiteralBrace(node, options) || noInner(node)) && !node.parent.hasEmpty) { - queue.push(utils.join(open, queue.pop() || '')); - queue = utils.flatten(utils.join(queue, close)); - } - - if (typeof last === 'undefined') { - prev.queue = [queue]; - } else { - prev.queue.push(utils.flatten(utils.join(last, queue))); - } - }) - - /** - * eos - */ - - .set('eos', function(node) { - if (this.input) return; - - if (options.optimize !== false) { - this.output = utils.last(utils.flatten(this.ast.queue)); - } else if (Array.isArray(utils.last(this.ast.queue))) { - this.output = utils.flatten(this.ast.queue.pop()); - } else { - this.output = utils.flatten(this.ast.queue); - } - - if (node.parent.count > 1 && options.expand) { - this.output = multiply(this.output, node.parent.count); - } - - this.output = utils.arrayify(this.output); - this.ast.queue = []; - }); - -}; - -/** - * Multiply the segments in the current brace level - */ - -function multiply(queue, n, options) { - return utils.flatten(utils.repeat(utils.arrayify(queue), n)); -} - -/** - * Return true if `node` is escaped - */ - -function isEscaped(node) { - return node.escaped === true; -} - -/** - * Returns true if regex parens should be used for sets. If the parent `type` - * is not `brace`, then we're on a root node, which means we should never - * expand segments and open/close braces should be `{}` (since this indicates - * a brace is missing from the set) - */ - -function isOptimized(node, options) { - if (node.parent.isOptimized) return true; - return isType(node.parent, 'brace') - && !isEscaped(node.parent) - && options.expand !== true; -} - -/** - * Returns true if the value in `node` should be wrapped in a literal brace. - * @return {Boolean} - */ - -function isLiteralBrace(node, options) { - return isEscaped(node.parent) || options.optimize !== false; -} - -/** - * Returns true if the given `node` does not have an inner value. - * @return {Boolean} - */ - -function noInner(node, type) { - if (node.parent.queue.length === 1) { - return true; - } - var nodes = node.parent.nodes; - return nodes.length === 3 - && isType(nodes[0], 'brace.open') - && !isType(nodes[1], 'text') - && isType(nodes[2], 'brace.close'); -} - -/** - * Returns true if the given `node` is the given `type` - * @return {Boolean} - */ - -function isType(node, type) { - return typeof node !== 'undefined' && node.type === type; -} - -/** - * Returns true if the given `node` has a non-empty queue. - * @return {Boolean} - */ - -function hasQueue(node) { - return Array.isArray(node.queue) && node.queue.length; -} - - -/***/ }), -/* 743 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var splitString = __webpack_require__(744); -var utils = module.exports; - -/** - * Module dependencies - */ - -utils.extend = __webpack_require__(738); -utils.flatten = __webpack_require__(750); -utils.isObject = __webpack_require__(748); -utils.fillRange = __webpack_require__(751); -utils.repeat = __webpack_require__(756); -utils.unique = __webpack_require__(741); - -utils.define = function(obj, key, val) { - Object.defineProperty(obj, key, { - writable: true, - configurable: true, - enumerable: false, - value: val - }); -}; - -/** - * Returns true if the given string contains only empty brace sets. - */ - -utils.isEmptySets = function(str) { - return /^(?:\{,\})+$/.test(str); -}; - -/** - * Returns true if the given string contains only empty brace sets. - */ - -utils.isQuotedString = function(str) { - var open = str.charAt(0); - if (open === '\'' || open === '"' || open === '`') { - return str.slice(-1) === open; - } - return false; -}; - -/** - * Create the key to use for memoization. The unique key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ - -utils.createKey = function(pattern, options) { - var id = pattern; - if (typeof options === 'undefined') { - return id; - } - var keys = Object.keys(options); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - id += ';' + key + '=' + String(options[key]); - } - return id; -}; - -/** - * Normalize options - */ - -utils.createOptions = function(options) { - var opts = utils.extend.apply(null, arguments); - if (typeof opts.expand === 'boolean') { - opts.optimize = !opts.expand; - } - if (typeof opts.optimize === 'boolean') { - opts.expand = !opts.optimize; - } - if (opts.optimize === true) { - opts.makeRe = true; - } - return opts; -}; - -/** - * Join patterns in `a` to patterns in `b` - */ - -utils.join = function(a, b, options) { - options = options || {}; - a = utils.arrayify(a); - b = utils.arrayify(b); - - if (!a.length) return b; - if (!b.length) return a; - - var len = a.length; - var idx = -1; - var arr = []; - - while (++idx < len) { - var val = a[idx]; - if (Array.isArray(val)) { - for (var i = 0; i < val.length; i++) { - val[i] = utils.join(val[i], b, options); - } - arr.push(val); - continue; - } - - for (var j = 0; j < b.length; j++) { - var bval = b[j]; - - if (Array.isArray(bval)) { - arr.push(utils.join(val, bval, options)); - } else { - arr.push(val + bval); - } - } - } - return arr; -}; - -/** - * Split the given string on `,` if not escaped. - */ - -utils.split = function(str, options) { - var opts = utils.extend({sep: ','}, options); - if (typeof opts.keepQuotes !== 'boolean') { - opts.keepQuotes = true; - } - if (opts.unescape === false) { - opts.keepEscaping = true; - } - return splitString(str, opts, utils.escapeBrackets(opts)); -}; - -/** - * Expand ranges or sets in the given `pattern`. - * - * @param {String} `str` - * @param {Object} `options` - * @return {Object} - */ - -utils.expand = function(str, options) { - var opts = utils.extend({rangeLimit: 10000}, options); - var segs = utils.split(str, opts); - var tok = { segs: segs }; - - if (utils.isQuotedString(str)) { - return tok; - } - - if (opts.rangeLimit === true) { - opts.rangeLimit = 10000; - } - - if (segs.length > 1) { - if (opts.optimize === false) { - tok.val = segs[0]; - return tok; - } - - tok.segs = utils.stringifyArray(tok.segs); - } else if (segs.length === 1) { - var arr = str.split('..'); - - if (arr.length === 1) { - tok.val = tok.segs[tok.segs.length - 1] || tok.val || str; - tok.segs = []; - return tok; - } - - if (arr.length === 2 && arr[0] === arr[1]) { - tok.escaped = true; - tok.val = arr[0]; - tok.segs = []; - return tok; - } - - if (arr.length > 1) { - if (opts.optimize !== false) { - opts.optimize = true; - delete opts.expand; - } - - if (opts.optimize !== true) { - var min = Math.min(arr[0], arr[1]); - var max = Math.max(arr[0], arr[1]); - var step = arr[2] || 1; - - if (opts.rangeLimit !== false && ((max - min) / step >= opts.rangeLimit)) { - throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); - } - } - - arr.push(opts); - tok.segs = utils.fillRange.apply(null, arr); - - if (!tok.segs.length) { - tok.escaped = true; - tok.val = str; - return tok; - } - - if (opts.optimize === true) { - tok.segs = utils.stringifyArray(tok.segs); - } - - if (tok.segs === '') { - tok.val = str; - } else { - tok.val = tok.segs[0]; - } - return tok; - } - } else { - tok.val = str; - } - return tok; -}; - -/** - * Ensure commas inside brackets and parens are not split. - * @param {Object} `tok` Token from the `split-string` module - * @return {undefined} - */ - -utils.escapeBrackets = function(options) { - return function(tok) { - if (tok.escaped && tok.val === 'b') { - tok.val = '\\b'; - return; - } - - if (tok.val !== '(' && tok.val !== '[') return; - var opts = utils.extend({}, options); - var brackets = []; - var parens = []; - var stack = []; - var val = tok.val; - var str = tok.str; - var i = tok.idx - 1; - - while (++i < str.length) { - var ch = str[i]; - - if (ch === '\\') { - val += (opts.keepEscaping === false ? '' : ch) + str[++i]; - continue; - } - - if (ch === '(') { - parens.push(ch); - stack.push(ch); - } - - if (ch === '[') { - brackets.push(ch); - stack.push(ch); - } - - if (ch === ')') { - parens.pop(); - stack.pop(); - if (!stack.length) { - val += ch; - break; - } - } - - if (ch === ']') { - brackets.pop(); - stack.pop(); - if (!stack.length) { - val += ch; - break; - } - } - val += ch; - } - - tok.split = false; - tok.val = val.slice(1); - tok.idx = i; - }; -}; - -/** - * Returns true if the given string looks like a regex quantifier - * @return {Boolean} - */ - -utils.isQuantifier = function(str) { - return /^(?:[0-9]?,[0-9]|[0-9],)$/.test(str); -}; - -/** - * Cast `val` to an array. - * @param {*} `val` - */ - -utils.stringifyArray = function(arr) { - return [utils.arrayify(arr).join('|')]; -}; - -/** - * Cast `val` to an array. - * @param {*} `val` - */ - -utils.arrayify = function(arr) { - if (typeof arr === 'undefined') { - return []; - } - if (typeof arr === 'string') { - return [arr]; - } - return arr; -}; - -/** - * Returns true if the given `str` is a non-empty string - * @return {Boolean} - */ - -utils.isString = function(str) { - return str != null && typeof str === 'string'; -}; - -/** - * Get the last element from `array` - * @param {Array} `array` - * @return {*} - */ - -utils.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; - -utils.escapeRegex = function(str) { - return str.replace(/\\?([!^*?()[\]{}+?/])/g, '\\$1'); -}; - - -/***/ }), -/* 744 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * split-string - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var extend = __webpack_require__(745); - -module.exports = function(str, options, fn) { - if (typeof str !== 'string') { - throw new TypeError('expected a string'); - } - - if (typeof options === 'function') { - fn = options; - options = null; - } - - // allow separator to be defined as a string - if (typeof options === 'string') { - options = { sep: options }; - } - - var opts = extend({sep: '.'}, options); - var quotes = opts.quotes || ['"', "'", '`']; - var brackets; - - if (opts.brackets === true) { - brackets = { - '<': '>', - '(': ')', - '[': ']', - '{': '}' - }; - } else if (opts.brackets) { - brackets = opts.brackets; - } - - var tokens = []; - var stack = []; - var arr = ['']; - var sep = opts.sep; - var len = str.length; - var idx = -1; - var closeIdx; - - function expected() { - if (brackets && stack.length) { - return brackets[stack[stack.length - 1]]; - } - } - - while (++idx < len) { - var ch = str[idx]; - var next = str[idx + 1]; - var tok = { val: ch, idx: idx, arr: arr, str: str }; - tokens.push(tok); - - if (ch === '\\') { - tok.val = keepEscaping(opts, str, idx) === true ? (ch + next) : next; - tok.escaped = true; - if (typeof fn === 'function') { - fn(tok); - } - arr[arr.length - 1] += tok.val; - idx++; - continue; - } - - if (brackets && brackets[ch]) { - stack.push(ch); - var e = expected(); - var i = idx + 1; - - if (str.indexOf(e, i + 1) !== -1) { - while (stack.length && i < len) { - var s = str[++i]; - if (s === '\\') { - s++; - continue; - } - - if (quotes.indexOf(s) !== -1) { - i = getClosingQuote(str, s, i + 1); - continue; - } - - e = expected(); - if (stack.length && str.indexOf(e, i + 1) === -1) { - break; - } - - if (brackets[s]) { - stack.push(s); - continue; - } - - if (e === s) { - stack.pop(); - } - } - } - - closeIdx = i; - if (closeIdx === -1) { - arr[arr.length - 1] += ch; - continue; - } - - ch = str.slice(idx, closeIdx + 1); - tok.val = ch; - tok.idx = idx = closeIdx; - } - - if (quotes.indexOf(ch) !== -1) { - closeIdx = getClosingQuote(str, ch, idx + 1); - if (closeIdx === -1) { - arr[arr.length - 1] += ch; - continue; - } - - if (keepQuotes(ch, opts) === true) { - ch = str.slice(idx, closeIdx + 1); - } else { - ch = str.slice(idx + 1, closeIdx); - } - - tok.val = ch; - tok.idx = idx = closeIdx; - } - - if (typeof fn === 'function') { - fn(tok, tokens); - ch = tok.val; - idx = tok.idx; - } - - if (tok.val === sep && tok.split !== false) { - arr.push(''); - continue; - } - - arr[arr.length - 1] += tok.val; - } - - return arr; -}; - -function getClosingQuote(str, ch, i, brackets) { - var idx = str.indexOf(ch, i); - if (str.charAt(idx - 1) === '\\') { - return getClosingQuote(str, ch, idx + 1); - } - return idx; -} - -function keepQuotes(ch, opts) { - if (opts.keepDoubleQuotes === true && ch === '"') return true; - if (opts.keepSingleQuotes === true && ch === "'") return true; - return opts.keepQuotes; -} - -function keepEscaping(opts, str, idx) { - if (typeof opts.keepEscaping === 'function') { - return opts.keepEscaping(str, idx); - } - return opts.keepEscaping === true || str[idx + 1] === '\\'; -} - - -/***/ }), -/* 745 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isExtendable = __webpack_require__(746); -var assignSymbols = __webpack_require__(749); - -module.exports = Object.assign || function(obj/*, objects*/) { - if (obj === null || typeof obj === 'undefined') { - throw new TypeError('Cannot convert undefined or null to object'); - } - if (!isObject(obj)) { - obj = {}; - } - for (var i = 1; i < arguments.length; i++) { - var val = arguments[i]; - if (isString(val)) { - val = toObject(val); - } - if (isObject(val)) { - assign(obj, val); - assignSymbols(obj, val); - } - } - return obj; -}; - -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } - } -} - -function isString(val) { - return (val && typeof val === 'string'); -} - -function toObject(str) { - var obj = {}; - for (var i in str) { - obj[i] = str[i]; - } - return obj; -} - -function isObject(val) { - return (val && typeof val === 'object') || isExtendable(val); -} - -/** - * Returns true if the given `key` is an own property of `obj`. - */ - -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - -function isEnum(obj, key) { - return Object.prototype.propertyIsEnumerable.call(obj, key); -} - - -/***/ }), -/* 746 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isPlainObject = __webpack_require__(747); - -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); -}; - - -/***/ }), -/* 747 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-plain-object - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isObject = __webpack_require__(748); - -function isObjectObject(o) { - return isObject(o) === true - && Object.prototype.toString.call(o) === '[object Object]'; -} - -module.exports = function isPlainObject(o) { - var ctor,prot; - - if (isObjectObject(o) === false) return false; - - // If has modified constructor - ctor = o.constructor; - if (typeof ctor !== 'function') return false; - - // If has modified prototype - prot = ctor.prototype; - if (isObjectObject(prot) === false) return false; - - // If constructor does not have an Object-specific method - if (prot.hasOwnProperty('isPrototypeOf') === false) { - return false; - } - - // Most likely a plain Object - return true; -}; - - -/***/ }), -/* 748 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * isobject - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function isObject(val) { - return val != null && typeof val === 'object' && Array.isArray(val) === false; -}; - - -/***/ }), -/* 749 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * assign-symbols - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -module.exports = function(receiver, objects) { - if (receiver === null || typeof receiver === 'undefined') { - throw new TypeError('expected first argument to be an object.'); - } - - if (typeof objects === 'undefined' || typeof Symbol === 'undefined') { - return receiver; - } - - if (typeof Object.getOwnPropertySymbols !== 'function') { - return receiver; - } - - var isEnumerable = Object.prototype.propertyIsEnumerable; - var target = Object(receiver); - var len = arguments.length, i = 0; - - while (++i < len) { - var provider = Object(arguments[i]); - var names = Object.getOwnPropertySymbols(provider); - - for (var j = 0; j < names.length; j++) { - var key = names[j]; - - if (isEnumerable.call(provider, key)) { - target[key] = provider[key]; - } - } - } - return target; -}; - - -/***/ }), -/* 750 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * arr-flatten - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function (arr) { - return flat(arr, []); -}; - -function flat(arr, res) { - var i = 0, cur; - var len = arr.length; - for (; i < len; i++) { - cur = arr[i]; - Array.isArray(cur) ? flat(cur, res) : res.push(cur); - } - return res; -} - - -/***/ }), -/* 751 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * fill-range - * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var util = __webpack_require__(29); -var isNumber = __webpack_require__(752); -var extend = __webpack_require__(738); -var repeat = __webpack_require__(754); -var toRegex = __webpack_require__(755); - -/** - * Return a range of numbers or letters. - * - * @param {String} `start` Start of the range - * @param {String} `stop` End of the range - * @param {String} `step` Increment or decrement to use. - * @param {Function} `fn` Custom function to modify each element in the range. - * @return {Array} - */ - -function fillRange(start, stop, step, options) { - if (typeof start === 'undefined') { - return []; - } - - if (typeof stop === 'undefined' || start === stop) { - // special case, for handling negative zero - var isString = typeof start === 'string'; - if (isNumber(start) && !toNumber(start)) { - return [isString ? '0' : 0]; - } - return [start]; - } - - if (typeof step !== 'number' && typeof step !== 'string') { - options = step; - step = undefined; - } - - if (typeof options === 'function') { - options = { transform: options }; - } - - var opts = extend({step: step}, options); - if (opts.step && !isValidNumber(opts.step)) { - if (opts.strictRanges === true) { - throw new TypeError('expected options.step to be a number'); - } - return []; - } - - opts.isNumber = isValidNumber(start) && isValidNumber(stop); - if (!opts.isNumber && !isValid(start, stop)) { - if (opts.strictRanges === true) { - throw new RangeError('invalid range arguments: ' + util.inspect([start, stop])); - } - return []; - } - - opts.isPadded = isPadded(start) || isPadded(stop); - opts.toString = opts.stringify - || typeof opts.step === 'string' - || typeof start === 'string' - || typeof stop === 'string' - || !opts.isNumber; - - if (opts.isPadded) { - opts.maxLength = Math.max(String(start).length, String(stop).length); - } - - // support legacy minimatch/fill-range options - if (typeof opts.optimize === 'boolean') opts.toRegex = opts.optimize; - if (typeof opts.makeRe === 'boolean') opts.toRegex = opts.makeRe; - return expand(start, stop, opts); -} - -function expand(start, stop, options) { - var a = options.isNumber ? toNumber(start) : start.charCodeAt(0); - var b = options.isNumber ? toNumber(stop) : stop.charCodeAt(0); - - var step = Math.abs(toNumber(options.step)) || 1; - if (options.toRegex && step === 1) { - return toRange(a, b, start, stop, options); - } - - var zero = {greater: [], lesser: []}; - var asc = a < b; - var arr = new Array(Math.round((asc ? b - a : a - b) / step)); - var idx = 0; - - while (asc ? a <= b : a >= b) { - var val = options.isNumber ? a : String.fromCharCode(a); - if (options.toRegex && (val >= 0 || !options.isNumber)) { - zero.greater.push(val); - } else { - zero.lesser.push(Math.abs(val)); - } - - if (options.isPadded) { - val = zeros(val, options); - } - - if (options.toString) { - val = String(val); - } - - if (typeof options.transform === 'function') { - arr[idx++] = options.transform(val, a, b, step, idx, arr, options); - } else { - arr[idx++] = val; - } - - if (asc) { - a += step; - } else { - a -= step; - } - } - - if (options.toRegex === true) { - return toSequence(arr, zero, options); - } - return arr; -} - -function toRange(a, b, start, stop, options) { - if (options.isPadded) { - return toRegex(start, stop, options); - } - - if (options.isNumber) { - return toRegex(Math.min(a, b), Math.max(a, b), options); - } - - var start = String.fromCharCode(Math.min(a, b)); - var stop = String.fromCharCode(Math.max(a, b)); - return '[' + start + '-' + stop + ']'; -} - -function toSequence(arr, zeros, options) { - var greater = '', lesser = ''; - if (zeros.greater.length) { - greater = zeros.greater.join('|'); - } - if (zeros.lesser.length) { - lesser = '-(' + zeros.lesser.join('|') + ')'; - } - var res = greater && lesser - ? greater + '|' + lesser - : greater || lesser; - - if (options.capture) { - return '(' + res + ')'; - } - return res; -} - -function zeros(val, options) { - if (options.isPadded) { - var str = String(val); - var len = str.length; - var dash = ''; - if (str.charAt(0) === '-') { - dash = '-'; - str = str.slice(1); - } - var diff = options.maxLength - len; - var pad = repeat('0', diff); - val = (dash + pad + str); - } - if (options.stringify) { - return String(val); - } - return val; -} - -function toNumber(val) { - return Number(val) || 0; -} - -function isPadded(str) { - return /^-?0\d/.test(str); -} - -function isValid(min, max) { - return (isValidNumber(min) || isValidLetter(min)) - && (isValidNumber(max) || isValidLetter(max)); -} - -function isValidLetter(ch) { - return typeof ch === 'string' && ch.length === 1 && /^\w+$/.test(ch); -} - -function isValidNumber(n) { - return isNumber(n) && !/\./.test(n); -} - -/** - * Expose `fillRange` - * @type {Function} - */ - -module.exports = fillRange; - - -/***/ }), -/* 752 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-number - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var typeOf = __webpack_require__(753); - -module.exports = function isNumber(num) { - var type = typeOf(num); - - if (type === 'string') { - if (!num.trim()) return false; - } else if (type !== 'number') { - return false; - } - - return (num - num + 1) >= 0; -}; - - -/***/ }), -/* 753 */ -/***/ (function(module, exports, __webpack_require__) { - -var isBuffer = __webpack_require__(735); -var toString = Object.prototype.toString; - -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ - -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } - - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } - - // other objects - var type = toString.call(val); - - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - - // buffer - if (isBuffer(val)) { - return 'buffer'; - } - - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } - - // must be a plain object - return 'object'; -}; - - -/***/ }), -/* 754 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * repeat-string - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -/** - * Results cache - */ - -var res = ''; -var cache; - -/** - * Expose `repeat` - */ - -module.exports = repeat; - -/** - * Repeat the given `string` the specified `number` - * of times. - * - * **Example:** - * - * ```js - * var repeat = require('repeat-string'); - * repeat('A', 5); - * //=> AAAAA - * ``` - * - * @param {String} `string` The string to repeat - * @param {Number} `number` The number of times to repeat the string - * @return {String} Repeated string - * @api public - */ - -function repeat(str, num) { - if (typeof str !== 'string') { - throw new TypeError('expected a string'); - } - - // cover common, quick use cases - if (num === 1) return str; - if (num === 2) return str + str; - - var max = str.length * num; - if (cache !== str || typeof cache === 'undefined') { - cache = str; - res = ''; - } else if (res.length >= max) { - return res.substr(0, max); - } - - while (max > res.length && num > 1) { - if (num & 1) { - res += str; - } - - num >>= 1; - str += str; - } - - res += str; - res = res.substr(0, max); - return res; -} - - -/***/ }), -/* 755 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * to-regex-range - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var repeat = __webpack_require__(754); -var isNumber = __webpack_require__(752); -var cache = {}; - -function toRegexRange(min, max, options) { - if (isNumber(min) === false) { - throw new RangeError('toRegexRange: first argument is invalid.'); - } - - if (typeof max === 'undefined' || min === max) { - return String(min); - } - - if (isNumber(max) === false) { - throw new RangeError('toRegexRange: second argument is invalid.'); - } - - options = options || {}; - var relax = String(options.relaxZeros); - var shorthand = String(options.shorthand); - var capture = String(options.capture); - var key = min + ':' + max + '=' + relax + shorthand + capture; - if (cache.hasOwnProperty(key)) { - return cache[key].result; - } - - var a = Math.min(min, max); - var b = Math.max(min, max); - - if (Math.abs(a - b) === 1) { - var result = min + '|' + max; - if (options.capture) { - return '(' + result + ')'; - } - return result; - } - - var isPadded = padding(min) || padding(max); - var positives = []; - var negatives = []; - - var tok = {min: min, max: max, a: a, b: b}; - if (isPadded) { - tok.isPadded = isPadded; - tok.maxLen = String(tok.max).length; - } - - if (a < 0) { - var newMin = b < 0 ? Math.abs(b) : 1; - var newMax = Math.abs(a); - negatives = splitToPatterns(newMin, newMax, tok, options); - a = tok.a = 0; - } - - if (b >= 0) { - positives = splitToPatterns(a, b, tok, options); - } - - tok.negatives = negatives; - tok.positives = positives; - tok.result = siftPatterns(negatives, positives, options); - - if (options.capture && (positives.length + negatives.length) > 1) { - tok.result = '(' + tok.result + ')'; - } - - cache[key] = tok; - return tok.result; -} - -function siftPatterns(neg, pos, options) { - var onlyNegative = filterPatterns(neg, pos, '-', false, options) || []; - var onlyPositive = filterPatterns(pos, neg, '', false, options) || []; - var intersected = filterPatterns(neg, pos, '-?', true, options) || []; - var subpatterns = onlyNegative.concat(intersected).concat(onlyPositive); - return subpatterns.join('|'); -} - -function splitToRanges(min, max) { - min = Number(min); - max = Number(max); - - var nines = 1; - var stops = [max]; - var stop = +countNines(min, nines); - - while (min <= stop && stop <= max) { - stops = push(stops, stop); - nines += 1; - stop = +countNines(min, nines); - } - - var zeros = 1; - stop = countZeros(max + 1, zeros) - 1; - - while (min < stop && stop <= max) { - stops = push(stops, stop); - zeros += 1; - stop = countZeros(max + 1, zeros) - 1; - } - - stops.sort(compare); - return stops; -} - -/** - * Convert a range to a regex pattern - * @param {Number} `start` - * @param {Number} `stop` - * @return {String} - */ - -function rangeToPattern(start, stop, options) { - if (start === stop) { - return {pattern: String(start), digits: []}; - } - - var zipped = zip(String(start), String(stop)); - var len = zipped.length, i = -1; - - var pattern = ''; - var digits = 0; - - while (++i < len) { - var numbers = zipped[i]; - var startDigit = numbers[0]; - var stopDigit = numbers[1]; - - if (startDigit === stopDigit) { - pattern += startDigit; - - } else if (startDigit !== '0' || stopDigit !== '9') { - pattern += toCharacterClass(startDigit, stopDigit); - - } else { - digits += 1; - } - } - - if (digits) { - pattern += options.shorthand ? '\\d' : '[0-9]'; - } - - return { pattern: pattern, digits: [digits] }; -} - -function splitToPatterns(min, max, tok, options) { - var ranges = splitToRanges(min, max); - var len = ranges.length; - var idx = -1; - - var tokens = []; - var start = min; - var prev; - - while (++idx < len) { - var range = ranges[idx]; - var obj = rangeToPattern(start, range, options); - var zeros = ''; - - if (!tok.isPadded && prev && prev.pattern === obj.pattern) { - if (prev.digits.length > 1) { - prev.digits.pop(); - } - prev.digits.push(obj.digits[0]); - prev.string = prev.pattern + toQuantifier(prev.digits); - start = range + 1; - continue; - } - - if (tok.isPadded) { - zeros = padZeros(range, tok); - } - - obj.string = zeros + obj.pattern + toQuantifier(obj.digits); - tokens.push(obj); - start = range + 1; - prev = obj; - } - - return tokens; -} - -function filterPatterns(arr, comparison, prefix, intersection, options) { - var res = []; - - for (var i = 0; i < arr.length; i++) { - var tok = arr[i]; - var ele = tok.string; - - if (options.relaxZeros !== false) { - if (prefix === '-' && ele.charAt(0) === '0') { - if (ele.charAt(1) === '{') { - ele = '0*' + ele.replace(/^0\{\d+\}/, ''); - } else { - ele = '0*' + ele.slice(1); - } - } - } - - if (!intersection && !contains(comparison, 'string', ele)) { - res.push(prefix + ele); - } - - if (intersection && contains(comparison, 'string', ele)) { - res.push(prefix + ele); - } - } - return res; -} - -/** - * Zip strings (`for in` can be used on string characters) - */ - -function zip(a, b) { - var arr = []; - for (var ch in a) arr.push([a[ch], b[ch]]); - return arr; -} - -function compare(a, b) { - return a > b ? 1 : b > a ? -1 : 0; -} - -function push(arr, ele) { - if (arr.indexOf(ele) === -1) arr.push(ele); - return arr; -} - -function contains(arr, key, val) { - for (var i = 0; i < arr.length; i++) { - if (arr[i][key] === val) { - return true; - } - } - return false; -} - -function countNines(min, len) { - return String(min).slice(0, -len) + repeat('9', len); -} - -function countZeros(integer, zeros) { - return integer - (integer % Math.pow(10, zeros)); -} - -function toQuantifier(digits) { - var start = digits[0]; - var stop = digits[1] ? (',' + digits[1]) : ''; - if (!stop && (!start || start === 1)) { - return ''; - } - return '{' + start + stop + '}'; -} - -function toCharacterClass(a, b) { - return '[' + a + ((b - a === 1) ? '' : '-') + b + ']'; -} - -function padding(str) { - return /^-?(0+)\d/.exec(str); -} - -function padZeros(val, tok) { - if (tok.isPadded) { - var diff = Math.abs(tok.maxLen - String(val).length); - switch (diff) { - case 0: - return ''; - case 1: - return '0'; - default: { - return '0{' + diff + '}'; - } - } - } - return val; -} - -/** - * Expose `toRegexRange` - */ - -module.exports = toRegexRange; - - -/***/ }), -/* 756 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * repeat-element - * - * Copyright (c) 2015 Jon Schlinkert. - * Licensed under the MIT license. - */ - - - -module.exports = function repeat(ele, num) { - var arr = new Array(num); - - for (var i = 0; i < num; i++) { - arr[i] = ele; - } - - return arr; -}; - - -/***/ }), -/* 757 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var Node = __webpack_require__(758); -var utils = __webpack_require__(743); - -/** - * Braces parsers - */ - -module.exports = function(braces, options) { - braces.parser - .set('bos', function() { - if (!this.parsed) { - this.ast = this.nodes[0] = new Node(this.ast); - } - }) - - /** - * Character parsers - */ - - .set('escape', function() { - var pos = this.position(); - var m = this.match(/^(?:\\(.)|\$\{)/); - if (!m) return; - - var prev = this.prev(); - var last = utils.last(prev.nodes); - - var node = pos(new Node({ - type: 'text', - multiplier: 1, - val: m[0] - })); - - if (node.val === '\\\\') { - return node; - } - - if (node.val === '${') { - var str = this.input; - var idx = -1; - var ch; - - while ((ch = str[++idx])) { - this.consume(1); - node.val += ch; - if (ch === '\\') { - node.val += str[++idx]; - continue; - } - if (ch === '}') { - break; - } - } - } - - if (this.options.unescape !== false) { - node.val = node.val.replace(/\\([{}])/g, '$1'); - } - - if (last.val === '"' && this.input.charAt(0) === '"') { - last.val = node.val; - this.consume(1); - return; - } - - return concatNodes.call(this, pos, node, prev, options); - }) - - /** - * Brackets: "[...]" (basic, this is overridden by - * other parsers in more advanced implementations) - */ - - .set('bracket', function() { - var isInside = this.isInside('brace'); - var pos = this.position(); - var m = this.match(/^(?:\[([!^]?)([^\]]{2,}|\]-)(\]|[^*+?]+)|\[)/); - if (!m) return; - - var prev = this.prev(); - var val = m[0]; - var negated = m[1] ? '^' : ''; - var inner = m[2] || ''; - var close = m[3] || ''; - - if (isInside && prev.type === 'brace') { - prev.text = prev.text || ''; - prev.text += val; - } - - var esc = this.input.slice(0, 2); - if (inner === '' && esc === '\\]') { - inner += esc; - this.consume(2); - - var str = this.input; - var idx = -1; - var ch; - - while ((ch = str[++idx])) { - this.consume(1); - if (ch === ']') { - close = ch; - break; - } - inner += ch; - } - } - - return pos(new Node({ - type: 'bracket', - val: val, - escaped: close !== ']', - negated: negated, - inner: inner, - close: close - })); - }) - - /** - * Empty braces (we capture these early to - * speed up processing in the compiler) - */ - - .set('multiplier', function() { - var isInside = this.isInside('brace'); - var pos = this.position(); - var m = this.match(/^\{((?:,|\{,+\})+)\}/); - if (!m) return; - - this.multiplier = true; - var prev = this.prev(); - var val = m[0]; - - if (isInside && prev.type === 'brace') { - prev.text = prev.text || ''; - prev.text += val; - } - - var node = pos(new Node({ - type: 'text', - multiplier: 1, - match: m, - val: val - })); - - return concatNodes.call(this, pos, node, prev, options); - }) - - /** - * Open - */ - - .set('brace.open', function() { - var pos = this.position(); - var m = this.match(/^\{(?!(?:[^\\}]?|,+)\})/); - if (!m) return; - - var prev = this.prev(); - var last = utils.last(prev.nodes); - - // if the last parsed character was an extglob character - // we need to _not optimize_ the brace pattern because - // it might be mistaken for an extglob by a downstream parser - if (last && last.val && isExtglobChar(last.val.slice(-1))) { - last.optimize = false; - } - - var open = pos(new Node({ - type: 'brace.open', - val: m[0] - })); - - var node = pos(new Node({ - type: 'brace', - nodes: [] - })); - - node.push(open); - prev.push(node); - this.push('brace', node); - }) - - /** - * Close - */ - - .set('brace.close', function() { - var pos = this.position(); - var m = this.match(/^\}/); - if (!m || !m[0]) return; - - var brace = this.pop('brace'); - var node = pos(new Node({ - type: 'brace.close', - val: m[0] - })); - - if (!this.isType(brace, 'brace')) { - if (this.options.strict) { - throw new Error('missing opening "{"'); - } - node.type = 'text'; - node.multiplier = 0; - node.escaped = true; - return node; - } - - var prev = this.prev(); - var last = utils.last(prev.nodes); - if (last.text) { - var lastNode = utils.last(last.nodes); - if (lastNode.val === ')' && /[!@*?+]\(/.test(last.text)) { - var open = last.nodes[0]; - var text = last.nodes[1]; - if (open.type === 'brace.open' && text && text.type === 'text') { - text.optimize = false; - } - } - } - - if (brace.nodes.length > 2) { - var first = brace.nodes[1]; - if (first.type === 'text' && first.val === ',') { - brace.nodes.splice(1, 1); - brace.nodes.push(first); - } - } - - brace.push(node); - }) - - /** - * Capture boundary characters - */ - - .set('boundary', function() { - var pos = this.position(); - var m = this.match(/^[$^](?!\{)/); - if (!m) return; - return pos(new Node({ - type: 'text', - val: m[0] - })); - }) - - /** - * One or zero, non-comma characters wrapped in braces - */ - - .set('nobrace', function() { - var isInside = this.isInside('brace'); - var pos = this.position(); - var m = this.match(/^\{[^,]?\}/); - if (!m) return; - - var prev = this.prev(); - var val = m[0]; - - if (isInside && prev.type === 'brace') { - prev.text = prev.text || ''; - prev.text += val; - } - - return pos(new Node({ - type: 'text', - multiplier: 0, - val: val - })); - }) - - /** - * Text - */ - - .set('text', function() { - var isInside = this.isInside('brace'); - var pos = this.position(); - var m = this.match(/^((?!\\)[^${}[\]])+/); - if (!m) return; - - var prev = this.prev(); - var val = m[0]; - - if (isInside && prev.type === 'brace') { - prev.text = prev.text || ''; - prev.text += val; - } - - var node = pos(new Node({ - type: 'text', - multiplier: 1, - val: val - })); - - return concatNodes.call(this, pos, node, prev, options); - }); -}; - -/** - * Returns true if the character is an extglob character. - */ - -function isExtglobChar(ch) { - return ch === '!' || ch === '@' || ch === '*' || ch === '?' || ch === '+'; -} - -/** - * Combine text nodes, and calculate empty sets (`{,,}`) - * @param {Function} `pos` Function to calculate node position - * @param {Object} `node` AST node - * @return {Object} - */ - -function concatNodes(pos, node, parent, options) { - node.orig = node.val; - var prev = this.prev(); - var last = utils.last(prev.nodes); - var isEscaped = false; - - if (node.val.length > 1) { - var a = node.val.charAt(0); - var b = node.val.slice(-1); - - isEscaped = (a === '"' && b === '"') - || (a === "'" && b === "'") - || (a === '`' && b === '`'); - } - - if (isEscaped && options.unescape !== false) { - node.val = node.val.slice(1, node.val.length - 1); - node.escaped = true; - } - - if (node.match) { - var match = node.match[1]; - if (!match || match.indexOf('}') === -1) { - match = node.match[0]; - } - - // replace each set with a single "," - var val = match.replace(/\{/g, ',').replace(/\}/g, ''); - node.multiplier *= val.length; - node.val = ''; - } - - var simpleText = last.type === 'text' - && last.multiplier === 1 - && node.multiplier === 1 - && node.val; - - if (simpleText) { - last.val += node.val; - return; - } - - prev.push(node); -} - - -/***/ }), -/* 758 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(748); -var define = __webpack_require__(759); -var utils = __webpack_require__(766); -var ownNames; - -/** - * Create a new AST `Node` with the given `val` and `type`. - * - * ```js - * var node = new Node('*', 'Star'); - * var node = new Node({type: 'star', val: '*'}); - * ``` - * @name Node - * @param {String|Object} `val` Pass a matched substring, or an object to merge onto the node. - * @param {String} `type` The node type to use when `val` is a string. - * @return {Object} node instance - * @api public - */ - -function Node(val, type, parent) { - if (typeof type !== 'string') { - parent = type; - type = null; - } - - define(this, 'parent', parent); - define(this, 'isNode', true); - define(this, 'expect', null); - - if (typeof type !== 'string' && isObject(val)) { - lazyKeys(); - var keys = Object.keys(val); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - if (ownNames.indexOf(key) === -1) { - this[key] = val[key]; - } - } - } else { - this.type = type; - this.val = val; - } -} - -/** - * Returns true if the given value is a node. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({type: 'foo'}); - * console.log(Node.isNode(node)); //=> true - * console.log(Node.isNode({})); //=> false - * ``` - * @param {Object} `node` - * @returns {Boolean} - * @api public - */ - -Node.isNode = function(node) { - return utils.isNode(node); -}; - -/** - * Define a non-enumberable property on the node instance. - * Useful for adding properties that shouldn't be extended - * or visible during debugging. - * - * ```js - * var node = new Node(); - * node.define('foo', 'something non-enumerable'); - * ``` - * @param {String} `name` - * @param {any} `val` - * @return {Object} returns the node instance - * @api public - */ - -Node.prototype.define = function(name, val) { - define(this, name, val); - return this; -}; - -/** - * Returns true if `node.val` is an empty string, or `node.nodes` does - * not contain any non-empty text nodes. - * - * ```js - * var node = new Node({type: 'text'}); - * node.isEmpty(); //=> true - * node.val = 'foo'; - * node.isEmpty(); //=> false - * ``` - * @param {Function} `fn` (optional) Filter function that is called on `node` and/or child nodes. `isEmpty` will return false immediately when the filter function returns false on any nodes. - * @return {Boolean} - * @api public - */ - -Node.prototype.isEmpty = function(fn) { - return utils.isEmpty(this, fn); -}; - -/** - * Given node `foo` and node `bar`, push node `bar` onto `foo.nodes`, and - * set `foo` as `bar.parent`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * foo.push(bar); - * ``` - * @param {Object} `node` - * @return {Number} Returns the length of `node.nodes` - * @api public - */ - -Node.prototype.push = function(node) { - assert(Node.isNode(node), 'expected node to be an instance of Node'); - define(node, 'parent', this); - - this.nodes = this.nodes || []; - return this.nodes.push(node); -}; - -/** - * Given node `foo` and node `bar`, unshift node `bar` onto `foo.nodes`, and - * set `foo` as `bar.parent`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * foo.unshift(bar); - * ``` - * @param {Object} `node` - * @return {Number} Returns the length of `node.nodes` - * @api public - */ - -Node.prototype.unshift = function(node) { - assert(Node.isNode(node), 'expected node to be an instance of Node'); - define(node, 'parent', this); - - this.nodes = this.nodes || []; - return this.nodes.unshift(node); -}; - -/** - * Pop a node from `node.nodes`. - * - * ```js - * var node = new Node({type: 'foo'}); - * node.push(new Node({type: 'a'})); - * node.push(new Node({type: 'b'})); - * node.push(new Node({type: 'c'})); - * node.push(new Node({type: 'd'})); - * console.log(node.nodes.length); - * //=> 4 - * node.pop(); - * console.log(node.nodes.length); - * //=> 3 - * ``` - * @return {Number} Returns the popped `node` - * @api public - */ - -Node.prototype.pop = function() { - return this.nodes && this.nodes.pop(); -}; - -/** - * Shift a node from `node.nodes`. - * - * ```js - * var node = new Node({type: 'foo'}); - * node.push(new Node({type: 'a'})); - * node.push(new Node({type: 'b'})); - * node.push(new Node({type: 'c'})); - * node.push(new Node({type: 'd'})); - * console.log(node.nodes.length); - * //=> 4 - * node.shift(); - * console.log(node.nodes.length); - * //=> 3 - * ``` - * @return {Object} Returns the shifted `node` - * @api public - */ - -Node.prototype.shift = function() { - return this.nodes && this.nodes.shift(); -}; - -/** - * Remove `node` from `node.nodes`. - * - * ```js - * node.remove(childNode); - * ``` - * @param {Object} `node` - * @return {Object} Returns the removed node. - * @api public - */ - -Node.prototype.remove = function(node) { - assert(Node.isNode(node), 'expected node to be an instance of Node'); - this.nodes = this.nodes || []; - var idx = node.index; - if (idx !== -1) { - node.index = -1; - return this.nodes.splice(idx, 1); - } - return null; -}; - -/** - * Get the first child node from `node.nodes` that matches the given `type`. - * If `type` is a number, the child node at that index is returned. - * - * ```js - * var child = node.find(1); //<= index of the node to get - * var child = node.find('foo'); //<= node.type of a child node - * var child = node.find(/^(foo|bar)$/); //<= regex to match node.type - * var child = node.find(['foo', 'bar']); //<= array of node.type(s) - * ``` - * @param {String} `type` - * @return {Object} Returns a child node or undefined. - * @api public - */ - -Node.prototype.find = function(type) { - return utils.findNode(this.nodes, type); -}; - -/** - * Return true if the node is the given `type`. - * - * ```js - * var node = new Node({type: 'bar'}); - * cosole.log(node.isType('foo')); // false - * cosole.log(node.isType(/^(foo|bar)$/)); // true - * cosole.log(node.isType(['foo', 'bar'])); // true - * ``` - * @param {String} `type` - * @return {Boolean} - * @api public - */ - -Node.prototype.isType = function(type) { - return utils.isType(this, type); -}; - -/** - * Return true if the `node.nodes` has the given `type`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * foo.push(bar); - * - * cosole.log(foo.hasType('qux')); // false - * cosole.log(foo.hasType(/^(qux|bar)$/)); // true - * cosole.log(foo.hasType(['qux', 'bar'])); // true - * ``` - * @param {String} `type` - * @return {Boolean} - * @api public - */ - -Node.prototype.hasType = function(type) { - return utils.hasType(this, type); -}; - -/** - * Get the siblings array, or `null` if it doesn't exist. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * foo.push(bar); - * foo.push(baz); - * - * console.log(bar.siblings.length) // 2 - * console.log(baz.siblings.length) // 2 - * ``` - * @return {Array} - * @api public - */ - -Object.defineProperty(Node.prototype, 'siblings', { - set: function() { - throw new Error('node.siblings is a getter and cannot be defined'); - }, - get: function() { - return this.parent ? this.parent.nodes : null; - } -}); - -/** - * Get the node's current index from `node.parent.nodes`. - * This should always be correct, even when the parent adds nodes. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * var qux = new Node({type: 'qux'}); - * foo.push(bar); - * foo.push(baz); - * foo.unshift(qux); - * - * console.log(bar.index) // 1 - * console.log(baz.index) // 2 - * console.log(qux.index) // 0 - * ``` - * @return {Number} - * @api public - */ - -Object.defineProperty(Node.prototype, 'index', { - set: function(index) { - define(this, 'idx', index); - }, - get: function() { - if (!Array.isArray(this.siblings)) { - return -1; - } - var tok = this.idx !== -1 ? this.siblings[this.idx] : null; - if (tok !== this) { - this.idx = this.siblings.indexOf(this); - } - return this.idx; - } -}); - -/** - * Get the previous node from the siblings array or `null`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * foo.push(bar); - * foo.push(baz); - * - * console.log(baz.prev.type) // 'bar' - * ``` - * @return {Object} - * @api public - */ - -Object.defineProperty(Node.prototype, 'prev', { - set: function() { - throw new Error('node.prev is a getter and cannot be defined'); - }, - get: function() { - if (Array.isArray(this.siblings)) { - return this.siblings[this.index - 1] || this.parent.prev; - } - return null; - } -}); - -/** - * Get the siblings array, or `null` if it doesn't exist. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * foo.push(bar); - * foo.push(baz); - * - * console.log(bar.siblings.length) // 2 - * console.log(baz.siblings.length) // 2 - * ``` - * @return {Object} - * @api public - */ - -Object.defineProperty(Node.prototype, 'next', { - set: function() { - throw new Error('node.next is a getter and cannot be defined'); - }, - get: function() { - if (Array.isArray(this.siblings)) { - return this.siblings[this.index + 1] || this.parent.next; - } - return null; - } -}); - -/** - * Get the first node from `node.nodes`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * var qux = new Node({type: 'qux'}); - * foo.push(bar); - * foo.push(baz); - * foo.push(qux); - * - * console.log(foo.first.type) // 'bar' - * ``` - * @return {Object} The first node, or undefiend - * @api public - */ - -Object.defineProperty(Node.prototype, 'first', { - get: function() { - return this.nodes ? this.nodes[0] : null; - } -}); - -/** - * Get the last node from `node.nodes`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * var qux = new Node({type: 'qux'}); - * foo.push(bar); - * foo.push(baz); - * foo.push(qux); - * - * console.log(foo.last.type) // 'qux' - * ``` - * @return {Object} The last node, or undefiend - * @api public - */ - -Object.defineProperty(Node.prototype, 'last', { - get: function() { - return this.nodes ? utils.last(this.nodes) : null; - } -}); - -/** - * Get the last node from `node.nodes`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * var qux = new Node({type: 'qux'}); - * foo.push(bar); - * foo.push(baz); - * foo.push(qux); - * - * console.log(foo.last.type) // 'qux' - * ``` - * @return {Object} The last node, or undefiend - * @api public - */ - -Object.defineProperty(Node.prototype, 'scope', { - get: function() { - if (this.isScope !== true) { - return this.parent ? this.parent.scope : this; - } - return this; - } -}); - -/** - * Get own property names from Node prototype, but only the - * first time `Node` is instantiated - */ - -function lazyKeys() { - if (!ownNames) { - ownNames = Object.getOwnPropertyNames(Node.prototype); - } -} - -/** - * Simplified assertion. Throws an error is `val` is falsey. - */ - -function assert(val, message) { - if (!val) throw new Error(message); -} - -/** - * Expose `Node` - */ - -exports = module.exports = Node; - - -/***/ }), -/* 759 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isDescriptor = __webpack_require__(760); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } - - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; - - -/***/ }), -/* 760 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var typeOf = __webpack_require__(761); -var isAccessor = __webpack_require__(762); -var isData = __webpack_require__(764); - -module.exports = function isDescriptor(obj, key) { - if (typeOf(obj) !== 'object') { - return false; - } - if ('get' in obj) { - return isAccessor(obj, key); - } - return isData(obj, key); -}; - - -/***/ }), -/* 761 */ -/***/ (function(module, exports) { - -var toString = Object.prototype.toString; - -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; - - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; - } - - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; - - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; - - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; - - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; - - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; - - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; - } - - if (isGeneratorObj(val)) { - return 'generator'; - } - - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; - } - - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); -}; - -function ctorName(val) { - return typeof val.constructor === 'function' ? val.constructor.name : null; -} - -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} - -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} - -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; -} - -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; -} - -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; -} - -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} - -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; - } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; - } - } - return false; -} - -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ - -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); - } - return false; -} - - -/***/ }), -/* 762 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-accessor-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var typeOf = __webpack_require__(763); - -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' -}; - -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } - - if (typeOf(obj) !== 'object') { - return false; - } - - if (has(obj, 'value') || has(obj, 'writable')) { - return false; - } - - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; - } - - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; - } - - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { - continue; - } - - if (typeOf(obj[key]) === accessor[key]) { - continue; - } - - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -} - -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); -} - -/** - * Expose `isAccessorDescriptor` - */ - -module.exports = isAccessorDescriptor; - - -/***/ }), -/* 763 */ -/***/ (function(module, exports) { - -var toString = Object.prototype.toString; - -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; - - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; - } - - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; - - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; - - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; - - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; - - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; - - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; - } - - if (isGeneratorObj(val)) { - return 'generator'; - } - - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; - } - - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); -}; - -function ctorName(val) { - return typeof val.constructor === 'function' ? val.constructor.name : null; -} - -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} - -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} - -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; -} - -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; -} - -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; -} - -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} - -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; - } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; - } - } - return false; -} - -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ - -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); - } - return false; -} - - -/***/ }), -/* 764 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-data-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var typeOf = __webpack_require__(765); - -module.exports = function isDataDescriptor(obj, prop) { - // data descriptor properties - var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' - }; - - if (typeOf(obj) !== 'object') { - return false; - } - - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } - - if (!('value' in obj) && !('writable' in obj)) { - return false; - } - - for (var key in obj) { - if (key === 'value') continue; - - if (!data.hasOwnProperty(key)) { - continue; - } - - if (typeOf(obj[key]) === data[key]) { - continue; - } - - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -}; - - -/***/ }), -/* 765 */ -/***/ (function(module, exports) { - -var toString = Object.prototype.toString; - -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; - - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; - } - - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; - - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; - - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; - - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; - - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; - - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; - } - - if (isGeneratorObj(val)) { - return 'generator'; - } - - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; - } - - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); -}; - -function ctorName(val) { - return typeof val.constructor === 'function' ? val.constructor.name : null; -} - -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} - -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} - -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; -} - -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; -} - -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; -} - -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} - -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; - } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; - } - } - return false; -} - -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ - -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); - } - return false; -} - - -/***/ }), -/* 766 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var typeOf = __webpack_require__(753); -var utils = module.exports; - -/** - * Returns true if the given value is a node. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({type: 'foo'}); - * console.log(utils.isNode(node)); //=> true - * console.log(utils.isNode({})); //=> false - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {Boolean} - * @api public - */ - -utils.isNode = function(node) { - return typeOf(node) === 'object' && node.isNode === true; -}; - -/** - * Emit an empty string for the given `node`. - * - * ```js - * // do nothing for beginning-of-string - * snapdragon.compiler.set('bos', utils.noop); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {undefined} - * @api public - */ - -utils.noop = function(node) { - append(this, '', node); -}; - -/** - * Appdend `node.val` to `compiler.output`, exactly as it was created - * by the parser. - * - * ```js - * snapdragon.compiler.set('text', utils.identity); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {undefined} - * @api public - */ - -utils.identity = function(node) { - append(this, node.val, node); -}; - -/** - * Previously named `.emit`, this method appends the given `val` - * to `compiler.output` for the given node. Useful when you know - * what value should be appended advance, regardless of the actual - * value of `node.val`. - * - * ```js - * snapdragon.compiler - * .set('i', function(node) { - * this.mapVisit(node); - * }) - * .set('i.open', utils.append('')) - * .set('i.close', utils.append('')) - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {Function} Returns a compiler middleware function. - * @api public - */ - -utils.append = function(val) { - return function(node) { - append(this, val, node); - }; -}; - -/** - * Used in compiler middleware, this onverts an AST node into - * an empty `text` node and deletes `node.nodes` if it exists. - * The advantage of this method is that, as opposed to completely - * removing the node, indices will not need to be re-calculated - * in sibling nodes, and nothing is appended to the output. - * - * ```js - * utils.toNoop(node); - * // convert `node.nodes` to the given value instead of deleting it - * utils.toNoop(node, []); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Array} `nodes` Optionally pass a new `nodes` value, to replace the existing `node.nodes` array. - * @api public - */ - -utils.toNoop = function(node, nodes) { - if (nodes) { - node.nodes = nodes; - } else { - delete node.nodes; - node.type = 'text'; - node.val = ''; - } -}; - -/** - * Visit `node` with the given `fn`. The built-in `.visit` method in snapdragon - * automatically calls registered compilers, this allows you to pass a visitor - * function. - * - * ```js - * snapdragon.compiler.set('i', function(node) { - * utils.visit(node, function(childNode) { - * // do stuff with "childNode" - * return childNode; - * }); - * }); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `fn` - * @return {Object} returns the node after recursively visiting all child nodes. - * @api public - */ - -utils.visit = function(node, fn) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(fn), 'expected a visitor function'); - fn(node); - return node.nodes ? utils.mapVisit(node, fn) : node; -}; - -/** - * Map [visit](#visit) the given `fn` over `node.nodes`. This is called by - * [visit](#visit), use this method if you do not want `fn` to be called on - * the first node. - * - * ```js - * snapdragon.compiler.set('i', function(node) { - * utils.mapVisit(node, function(childNode) { - * // do stuff with "childNode" - * return childNode; - * }); - * }); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Object} `options` - * @param {Function} `fn` - * @return {Object} returns the node - * @api public - */ - -utils.mapVisit = function(node, fn) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isArray(node.nodes), 'expected node.nodes to be an array'); - assert(isFunction(fn), 'expected a visitor function'); - - for (var i = 0; i < node.nodes.length; i++) { - utils.visit(node.nodes[i], fn); - } - return node; -}; - -/** - * Unshift an `*.open` node onto `node.nodes`. - * - * ```js - * var Node = require('snapdragon-node'); - * snapdragon.parser.set('brace', function(node) { - * var match = this.match(/^{/); - * if (match) { - * var parent = new Node({type: 'brace'}); - * utils.addOpen(parent, Node); - * console.log(parent.nodes[0]): - * // { type: 'brace.open', val: '' }; - * - * // push the parent "brace" node onto the stack - * this.push(parent); - * - * // return the parent node, so it's also added to the AST - * return brace; - * } - * }); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. - * @param {Function} `filter` Optionaly specify a filter function to exclude the node. - * @return {Object} Returns the created opening node. - * @api public - */ - -utils.addOpen = function(node, Node, val, filter) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(Node), 'expected Node to be a constructor function'); - - if (typeof val === 'function') { - filter = val; - val = ''; - } - - if (typeof filter === 'function' && !filter(node)) return; - var open = new Node({ type: node.type + '.open', val: val}); - var unshift = node.unshift || node.unshiftNode; - if (typeof unshift === 'function') { - unshift.call(node, open); - } else { - utils.unshiftNode(node, open); - } - return open; -}; - -/** - * Push a `*.close` node onto `node.nodes`. - * - * ```js - * var Node = require('snapdragon-node'); - * snapdragon.parser.set('brace', function(node) { - * var match = this.match(/^}/); - * if (match) { - * var parent = this.parent(); - * if (parent.type !== 'brace') { - * throw new Error('missing opening: ' + '}'); - * } - * - * utils.addClose(parent, Node); - * console.log(parent.nodes[parent.nodes.length - 1]): - * // { type: 'brace.close', val: '' }; - * - * // no need to return a node, since the parent - * // was already added to the AST - * return; - * } - * }); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. - * @param {Function} `filter` Optionaly specify a filter function to exclude the node. - * @return {Object} Returns the created closing node. - * @api public - */ - -utils.addClose = function(node, Node, val, filter) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(Node), 'expected Node to be a constructor function'); - - if (typeof val === 'function') { - filter = val; - val = ''; - } - - if (typeof filter === 'function' && !filter(node)) return; - var close = new Node({ type: node.type + '.close', val: val}); - var push = node.push || node.pushNode; - if (typeof push === 'function') { - push.call(node, close); - } else { - utils.pushNode(node, close); - } - return close; -}; - -/** - * Wraps the given `node` with `*.open` and `*.close` nodes. - * - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. - * @param {Function} `filter` Optionaly specify a filter function to exclude the node. - * @return {Object} Returns the node - * @api public - */ - -utils.wrapNodes = function(node, Node, filter) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(Node), 'expected Node to be a constructor function'); - - utils.addOpen(node, Node, filter); - utils.addClose(node, Node, filter); - return node; -}; - -/** - * Push the given `node` onto `parent.nodes`, and set `parent` as `node.parent. - * - * ```js - * var parent = new Node({type: 'foo'}); - * var node = new Node({type: 'bar'}); - * utils.pushNode(parent, node); - * console.log(parent.nodes[0].type) // 'bar' - * console.log(node.parent.type) // 'foo' - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Object} Returns the child node - * @api public - */ - -utils.pushNode = function(parent, node) { - assert(utils.isNode(parent), 'expected parent node to be an instance of Node'); - assert(utils.isNode(node), 'expected node to be an instance of Node'); - - node.define('parent', parent); - parent.nodes = parent.nodes || []; - parent.nodes.push(node); - return node; -}; - -/** - * Unshift `node` onto `parent.nodes`, and set `parent` as `node.parent. - * - * ```js - * var parent = new Node({type: 'foo'}); - * var node = new Node({type: 'bar'}); - * utils.unshiftNode(parent, node); - * console.log(parent.nodes[0].type) // 'bar' - * console.log(node.parent.type) // 'foo' - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {undefined} - * @api public - */ - -utils.unshiftNode = function(parent, node) { - assert(utils.isNode(parent), 'expected parent node to be an instance of Node'); - assert(utils.isNode(node), 'expected node to be an instance of Node'); - - node.define('parent', parent); - parent.nodes = parent.nodes || []; - parent.nodes.unshift(node); -}; - -/** - * Pop the last `node` off of `parent.nodes`. The advantage of - * using this method is that it checks for `node.nodes` and works - * with any version of `snapdragon-node`. - * - * ```js - * var parent = new Node({type: 'foo'}); - * utils.pushNode(parent, new Node({type: 'foo'})); - * utils.pushNode(parent, new Node({type: 'bar'})); - * utils.pushNode(parent, new Node({type: 'baz'})); - * console.log(parent.nodes.length); //=> 3 - * utils.popNode(parent); - * console.log(parent.nodes.length); //=> 2 - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Number|Undefined} Returns the length of `node.nodes` or undefined. - * @api public - */ - -utils.popNode = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (typeof node.pop === 'function') { - return node.pop(); - } - return node.nodes && node.nodes.pop(); -}; - -/** - * Shift the first `node` off of `parent.nodes`. The advantage of - * using this method is that it checks for `node.nodes` and works - * with any version of `snapdragon-node`. - * - * ```js - * var parent = new Node({type: 'foo'}); - * utils.pushNode(parent, new Node({type: 'foo'})); - * utils.pushNode(parent, new Node({type: 'bar'})); - * utils.pushNode(parent, new Node({type: 'baz'})); - * console.log(parent.nodes.length); //=> 3 - * utils.shiftNode(parent); - * console.log(parent.nodes.length); //=> 2 - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Number|Undefined} Returns the length of `node.nodes` or undefined. - * @api public - */ - -utils.shiftNode = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (typeof node.shift === 'function') { - return node.shift(); - } - return node.nodes && node.nodes.shift(); -}; - -/** - * Remove the specified `node` from `parent.nodes`. - * - * ```js - * var parent = new Node({type: 'abc'}); - * var foo = new Node({type: 'foo'}); - * utils.pushNode(parent, foo); - * utils.pushNode(parent, new Node({type: 'bar'})); - * utils.pushNode(parent, new Node({type: 'baz'})); - * console.log(parent.nodes.length); //=> 3 - * utils.removeNode(parent, foo); - * console.log(parent.nodes.length); //=> 2 - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Object|undefined} Returns the removed node, if successful, or undefined if it does not exist on `parent.nodes`. - * @api public - */ - -utils.removeNode = function(parent, node) { - assert(utils.isNode(parent), 'expected parent.node to be an instance of Node'); - assert(utils.isNode(node), 'expected node to be an instance of Node'); - - if (!parent.nodes) { - return null; - } - - if (typeof parent.remove === 'function') { - return parent.remove(node); - } - - var idx = parent.nodes.indexOf(node); - if (idx !== -1) { - return parent.nodes.splice(idx, 1); - } -}; - -/** - * Returns true if `node.type` matches the given `type`. Throws a - * `TypeError` if `node` is not an instance of `Node`. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({type: 'foo'}); - * console.log(utils.isType(node, 'foo')); // false - * console.log(utils.isType(node, 'bar')); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {String} `type` - * @return {Boolean} - * @api public - */ - -utils.isType = function(node, type) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - switch (typeOf(type)) { - case 'array': - var types = type.slice(); - for (var i = 0; i < types.length; i++) { - if (utils.isType(node, types[i])) { - return true; - } - } - return false; - case 'string': - return node.type === type; - case 'regexp': - return type.test(node.type); - default: { - throw new TypeError('expected "type" to be an array, string or regexp'); - } - } -}; - -/** - * Returns true if the given `node` has the given `type` in `node.nodes`. - * Throws a `TypeError` if `node` is not an instance of `Node`. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({ - * type: 'foo', - * nodes: [ - * new Node({type: 'bar'}), - * new Node({type: 'baz'}) - * ] - * }); - * console.log(utils.hasType(node, 'xyz')); // false - * console.log(utils.hasType(node, 'baz')); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {String} `type` - * @return {Boolean} - * @api public - */ - -utils.hasType = function(node, type) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (!Array.isArray(node.nodes)) return false; - for (var i = 0; i < node.nodes.length; i++) { - if (utils.isType(node.nodes[i], type)) { - return true; - } - } - return false; -}; - -/** - * Returns the first node from `node.nodes` of the given `type` - * - * ```js - * var node = new Node({ - * type: 'foo', - * nodes: [ - * new Node({type: 'text', val: 'abc'}), - * new Node({type: 'text', val: 'xyz'}) - * ] - * }); - * - * var textNode = utils.firstOfType(node.nodes, 'text'); - * console.log(textNode.val); - * //=> 'abc' - * ``` - * @param {Array} `nodes` - * @param {String} `type` - * @return {Object|undefined} Returns the first matching node or undefined. - * @api public - */ - -utils.firstOfType = function(nodes, type) { - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i]; - if (utils.isType(node, type)) { - return node; - } - } -}; - -/** - * Returns the node at the specified index, or the first node of the - * given `type` from `node.nodes`. - * - * ```js - * var node = new Node({ - * type: 'foo', - * nodes: [ - * new Node({type: 'text', val: 'abc'}), - * new Node({type: 'text', val: 'xyz'}) - * ] - * }); - * - * var nodeOne = utils.findNode(node.nodes, 'text'); - * console.log(nodeOne.val); - * //=> 'abc' - * - * var nodeTwo = utils.findNode(node.nodes, 1); - * console.log(nodeTwo.val); - * //=> 'xyz' - * ``` - * - * @param {Array} `nodes` - * @param {String|Number} `type` Node type or index. - * @return {Object} Returns a node or undefined. - * @api public - */ - -utils.findNode = function(nodes, type) { - if (!Array.isArray(nodes)) { - return null; - } - if (typeof type === 'number') { - return nodes[type]; - } - return utils.firstOfType(nodes, type); -}; - -/** - * Returns true if the given node is an "*.open" node. - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({type: 'brace'}); - * var open = new Node({type: 'brace.open'}); - * var close = new Node({type: 'brace.close'}); - * - * console.log(utils.isOpen(brace)); // false - * console.log(utils.isOpen(open)); // true - * console.log(utils.isOpen(close)); // false - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ - -utils.isOpen = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - return node.type.slice(-5) === '.open'; -}; - -/** - * Returns true if the given node is a "*.close" node. - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({type: 'brace'}); - * var open = new Node({type: 'brace.open'}); - * var close = new Node({type: 'brace.close'}); - * - * console.log(utils.isClose(brace)); // false - * console.log(utils.isClose(open)); // false - * console.log(utils.isClose(close)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ - -utils.isClose = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - return node.type.slice(-6) === '.close'; -}; - -/** - * Returns true if `node.nodes` **has** an `.open` node - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({ - * type: 'brace', - * nodes: [] - * }); - * - * var open = new Node({type: 'brace.open'}); - * console.log(utils.hasOpen(brace)); // false - * - * brace.pushNode(open); - * console.log(utils.hasOpen(brace)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ - -utils.hasOpen = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - var first = node.first || node.nodes ? node.nodes[0] : null; - if (utils.isNode(first)) { - return first.type === node.type + '.open'; - } - return false; -}; - -/** - * Returns true if `node.nodes` **has** a `.close` node - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({ - * type: 'brace', - * nodes: [] - * }); - * - * var close = new Node({type: 'brace.close'}); - * console.log(utils.hasClose(brace)); // false - * - * brace.pushNode(close); - * console.log(utils.hasClose(brace)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ - -utils.hasClose = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - var last = node.last || node.nodes ? node.nodes[node.nodes.length - 1] : null; - if (utils.isNode(last)) { - return last.type === node.type + '.close'; - } - return false; -}; - -/** - * Returns true if `node.nodes` has both `.open` and `.close` nodes - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({ - * type: 'brace', - * nodes: [] - * }); - * - * var open = new Node({type: 'brace.open'}); - * var close = new Node({type: 'brace.close'}); - * console.log(utils.hasOpen(brace)); // false - * console.log(utils.hasClose(brace)); // false - * - * brace.pushNode(open); - * brace.pushNode(close); - * console.log(utils.hasOpen(brace)); // true - * console.log(utils.hasClose(brace)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ - -utils.hasOpenAndClose = function(node) { - return utils.hasOpen(node) && utils.hasClose(node); -}; - -/** - * Push the given `node` onto the `state.inside` array for the - * given type. This array is used as a specialized "stack" for - * only the given `node.type`. - * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * utils.addType(state, node); - * console.log(state.inside); - * //=> { brace: [{type: 'brace'}] } - * ``` - * @param {Object} `state` The `compiler.state` object or custom state object. - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Array} Returns the `state.inside` stack for the given type. - * @api public - */ - -utils.addType = function(state, node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isObject(state), 'expected state to be an object'); - - var type = node.parent - ? node.parent.type - : node.type.replace(/\.open$/, ''); - - if (!state.hasOwnProperty('inside')) { - state.inside = {}; - } - if (!state.inside.hasOwnProperty(type)) { - state.inside[type] = []; - } - - var arr = state.inside[type]; - arr.push(node); - return arr; -}; - -/** - * Remove the given `node` from the `state.inside` array for the - * given type. This array is used as a specialized "stack" for - * only the given `node.type`. - * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * utils.addType(state, node); - * console.log(state.inside); - * //=> { brace: [{type: 'brace'}] } - * utils.removeType(state, node); - * //=> { brace: [] } - * ``` - * @param {Object} `state` The `compiler.state` object or custom state object. - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Array} Returns the `state.inside` stack for the given type. - * @api public - */ - -utils.removeType = function(state, node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isObject(state), 'expected state to be an object'); - - var type = node.parent - ? node.parent.type - : node.type.replace(/\.close$/, ''); - - if (state.inside.hasOwnProperty(type)) { - return state.inside[type].pop(); - } -}; - -/** - * Returns true if `node.val` is an empty string, or `node.nodes` does - * not contain any non-empty text nodes. - * - * ```js - * var node = new Node({type: 'text'}); - * utils.isEmpty(node); //=> true - * node.val = 'foo'; - * utils.isEmpty(node); //=> false - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `fn` - * @return {Boolean} - * @api public - */ - -utils.isEmpty = function(node, fn) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - - if (!Array.isArray(node.nodes)) { - if (node.type !== 'text') { - return true; - } - if (typeof fn === 'function') { - return fn(node, node.parent); - } - return !utils.trim(node.val); - } - - for (var i = 0; i < node.nodes.length; i++) { - var child = node.nodes[i]; - if (utils.isOpen(child) || utils.isClose(child)) { - continue; - } - if (!utils.isEmpty(child, fn)) { - return false; - } - } - - return true; -}; - -/** - * Returns true if the `state.inside` stack for the given type exists - * and has one or more nodes on it. - * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * console.log(utils.isInsideType(state, 'brace')); //=> false - * utils.addType(state, node); - * console.log(utils.isInsideType(state, 'brace')); //=> true - * utils.removeType(state, node); - * console.log(utils.isInsideType(state, 'brace')); //=> false - * ``` - * @param {Object} `state` - * @param {String} `type` - * @return {Boolean} - * @api public - */ - -utils.isInsideType = function(state, type) { - assert(isObject(state), 'expected state to be an object'); - assert(isString(type), 'expected type to be a string'); - - if (!state.hasOwnProperty('inside')) { - return false; - } - - if (!state.inside.hasOwnProperty(type)) { - return false; - } - - return state.inside[type].length > 0; -}; - -/** - * Returns true if `node` is either a child or grand-child of the given `type`, - * or `state.inside[type]` is a non-empty array. - * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * var open = new Node({type: 'brace.open'}); - * console.log(utils.isInside(state, open, 'brace')); //=> false - * utils.pushNode(node, open); - * console.log(utils.isInside(state, open, 'brace')); //=> true - * ``` - * @param {Object} `state` Either the `compiler.state` object, if it exists, or a user-supplied state object. - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {String} `type` The `node.type` to check for. - * @return {Boolean} - * @api public - */ - -utils.isInside = function(state, node, type) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isObject(state), 'expected state to be an object'); - - if (Array.isArray(type)) { - for (var i = 0; i < type.length; i++) { - if (utils.isInside(state, node, type[i])) { - return true; - } - } - return false; - } - - var parent = node.parent; - if (typeof type === 'string') { - return (parent && parent.type === type) || utils.isInsideType(state, type); - } - - if (typeOf(type) === 'regexp') { - if (parent && parent.type && type.test(parent.type)) { - return true; - } - - var keys = Object.keys(state.inside); - var len = keys.length; - var idx = -1; - while (++idx < len) { - var key = keys[idx]; - var val = state.inside[key]; - - if (Array.isArray(val) && val.length !== 0 && type.test(key)) { - return true; - } - } - } - return false; -}; - -/** - * Get the last `n` element from the given `array`. Used for getting - * a node from `node.nodes.` - * - * @param {Array} `array` - * @param {Number} `n` - * @return {undefined} - * @api public - */ - -utils.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; - -/** - * Cast the given `val` to an array. - * - * ```js - * console.log(utils.arrayify('')); - * //=> [] - * console.log(utils.arrayify('foo')); - * //=> ['foo'] - * console.log(utils.arrayify(['foo'])); - * //=> ['foo'] - * ``` - * @param {any} `val` - * @return {Array} - * @api public - */ - -utils.arrayify = function(val) { - if (typeof val === 'string' && val !== '') { - return [val]; - } - if (!Array.isArray(val)) { - return []; - } - return val; -}; - -/** - * Convert the given `val` to a string by joining with `,`. Useful - * for creating a cheerio/CSS/DOM-style selector from a list of strings. - * - * @param {any} `val` - * @return {Array} - * @api public - */ - -utils.stringify = function(val) { - return utils.arrayify(val).join(','); -}; - -/** - * Ensure that the given value is a string and call `.trim()` on it, - * or return an empty string. - * - * @param {String} `str` - * @return {String} - * @api public - */ - -utils.trim = function(str) { - return typeof str === 'string' ? str.trim() : ''; -}; - -/** - * Return true if val is an object - */ - -function isObject(val) { - return typeOf(val) === 'object'; -} - -/** - * Return true if val is a string - */ - -function isString(val) { - return typeof val === 'string'; -} - -/** - * Return true if val is a function - */ - -function isFunction(val) { - return typeof val === 'function'; -} - -/** - * Return true if val is an array - */ - -function isArray(val) { - return Array.isArray(val); -} - -/** - * Shim to ensure the `.append` methods work with any version of snapdragon - */ - -function append(compiler, val, node) { - if (typeof compiler.append !== 'function') { - return compiler.emit(val, node); - } - return compiler.append(val, node); -} - -/** - * Simplified assertion. Throws an error is `val` is falsey. - */ - -function assert(val, message) { - if (!val) throw new Error(message); -} - - -/***/ }), -/* 767 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var extend = __webpack_require__(738); -var Snapdragon = __webpack_require__(768); -var compilers = __webpack_require__(742); -var parsers = __webpack_require__(757); -var utils = __webpack_require__(743); - -/** - * Customize Snapdragon parser and renderer - */ - -function Braces(options) { - this.options = extend({}, options); -} - -/** - * Initialize braces - */ - -Braces.prototype.init = function(options) { - if (this.isInitialized) return; - this.isInitialized = true; - var opts = utils.createOptions({}, this.options, options); - this.snapdragon = this.options.snapdragon || new Snapdragon(opts); - this.compiler = this.snapdragon.compiler; - this.parser = this.snapdragon.parser; - - compilers(this.snapdragon, opts); - parsers(this.snapdragon, opts); - - /** - * Call Snapdragon `.parse` method. When AST is returned, we check to - * see if any unclosed braces are left on the stack and, if so, we iterate - * over the stack and correct the AST so that compilers are called in the correct - * order and unbalance braces are properly escaped. - */ - - utils.define(this.snapdragon, 'parse', function(pattern, options) { - var parsed = Snapdragon.prototype.parse.apply(this, arguments); - this.parser.ast.input = pattern; - - var stack = this.parser.stack; - while (stack.length) { - addParent({type: 'brace.close', val: ''}, stack.pop()); - } - - function addParent(node, parent) { - utils.define(node, 'parent', parent); - parent.nodes.push(node); - } - - // add non-enumerable parser reference - utils.define(parsed, 'parser', this.parser); - return parsed; - }); -}; - -/** - * Decorate `.parse` method - */ - -Braces.prototype.parse = function(ast, options) { - if (ast && typeof ast === 'object' && ast.nodes) return ast; - this.init(options); - return this.snapdragon.parse(ast, options); -}; - -/** - * Decorate `.compile` method - */ - -Braces.prototype.compile = function(ast, options) { - if (typeof ast === 'string') { - ast = this.parse(ast, options); - } else { - this.init(options); - } - return this.snapdragon.compile(ast, options); -}; - -/** - * Expand - */ - -Braces.prototype.expand = function(pattern) { - var ast = this.parse(pattern, {expand: true}); - return this.compile(ast, {expand: true}); -}; - -/** - * Optimize - */ - -Braces.prototype.optimize = function(pattern) { - var ast = this.parse(pattern, {optimize: true}); - return this.compile(ast, {optimize: true}); -}; - -/** - * Expose `Braces` - */ - -module.exports = Braces; - - -/***/ }), -/* 768 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var Base = __webpack_require__(769); -var define = __webpack_require__(730); -var Compiler = __webpack_require__(798); -var Parser = __webpack_require__(827); -var utils = __webpack_require__(807); -var regexCache = {}; -var cache = {}; - -/** - * Create a new instance of `Snapdragon` with the given `options`. - * - * ```js - * var snapdragon = new Snapdragon(); - * ``` - * - * @param {Object} `options` - * @api public - */ - -function Snapdragon(options) { - Base.call(this, null, options); - this.options = utils.extend({source: 'string'}, this.options); - this.compiler = new Compiler(this.options); - this.parser = new Parser(this.options); - - Object.defineProperty(this, 'compilers', { - get: function() { - return this.compiler.compilers; - } - }); - - Object.defineProperty(this, 'parsers', { - get: function() { - return this.parser.parsers; - } - }); - - Object.defineProperty(this, 'regex', { - get: function() { - return this.parser.regex; - } - }); -} - -/** - * Inherit Base - */ - -Base.extend(Snapdragon); - -/** - * Add a parser to `snapdragon.parsers` for capturing the given `type` using - * the specified regex or parser function. A function is useful if you need - * to customize how the token is created and/or have access to the parser - * instance to check options, etc. - * - * ```js - * snapdragon - * .capture('slash', /^\//) - * .capture('dot', function() { - * var pos = this.position(); - * var m = this.match(/^\./); - * if (!m) return; - * return pos({ - * type: 'dot', - * val: m[0] - * }); - * }); - * ``` - * @param {String} `type` - * @param {RegExp|Function} `regex` - * @return {Object} Returns the parser instance for chaining - * @api public - */ - -Snapdragon.prototype.capture = function() { - return this.parser.capture.apply(this.parser, arguments); -}; - -/** - * Register a plugin `fn`. - * - * ```js - * var snapdragon = new Snapdgragon([options]); - * snapdragon.use(function() { - * console.log(this); //<= snapdragon instance - * console.log(this.parser); //<= parser instance - * console.log(this.compiler); //<= compiler instance - * }); - * ``` - * @param {Object} `fn` - * @api public - */ - -Snapdragon.prototype.use = function(fn) { - fn.call(this, this); - return this; -}; - -/** - * Parse the given `str`. - * - * ```js - * var snapdragon = new Snapdgragon([options]); - * // register parsers - * snapdragon.parser.use(function() {}); - * - * // parse - * var ast = snapdragon.parse('foo/bar'); - * console.log(ast); - * ``` - * @param {String} `str` - * @param {Object} `options` Set `options.sourcemap` to true to enable source maps. - * @return {Object} Returns an AST. - * @api public - */ - -Snapdragon.prototype.parse = function(str, options) { - this.options = utils.extend({}, this.options, options); - var parsed = this.parser.parse(str, this.options); - - // add non-enumerable parser reference - define(parsed, 'parser', this.parser); - return parsed; -}; - -/** - * Compile the given `AST`. - * - * ```js - * var snapdragon = new Snapdgragon([options]); - * // register plugins - * snapdragon.use(function() {}); - * // register parser plugins - * snapdragon.parser.use(function() {}); - * // register compiler plugins - * snapdragon.compiler.use(function() {}); - * - * // parse - * var ast = snapdragon.parse('foo/bar'); - * - * // compile - * var res = snapdragon.compile(ast); - * console.log(res.output); - * ``` - * @param {Object} `ast` - * @param {Object} `options` - * @return {Object} Returns an object with an `output` property with the rendered string. - * @api public - */ - -Snapdragon.prototype.compile = function(ast, options) { - this.options = utils.extend({}, this.options, options); - var compiled = this.compiler.compile(ast, this.options); - - // add non-enumerable compiler reference - define(compiled, 'compiler', this.compiler); - return compiled; -}; - -/** - * Expose `Snapdragon` - */ - -module.exports = Snapdragon; - -/** - * Expose `Parser` and `Compiler` - */ - -module.exports.Compiler = Compiler; -module.exports.Parser = Parser; - - -/***/ }), -/* 769 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var util = __webpack_require__(29); -var define = __webpack_require__(770); -var CacheBase = __webpack_require__(771); -var Emitter = __webpack_require__(772); -var isObject = __webpack_require__(748); -var merge = __webpack_require__(789); -var pascal = __webpack_require__(792); -var cu = __webpack_require__(793); - -/** - * Optionally define a custom `cache` namespace to use. - */ - -function namespace(name) { - var Cache = name ? CacheBase.namespace(name) : CacheBase; - var fns = []; - - /** - * Create an instance of `Base` with the given `config` and `options`. - * - * ```js - * // initialize with `config` and `options` - * var app = new Base({isApp: true}, {abc: true}); - * app.set('foo', 'bar'); - * - * // values defined with the given `config` object will be on the root of the instance - * console.log(app.baz); //=> undefined - * console.log(app.foo); //=> 'bar' - * // or use `.get` - * console.log(app.get('isApp')); //=> true - * console.log(app.get('foo')); //=> 'bar' - * - * // values defined with the given `options` object will be on `app.options - * console.log(app.options.abc); //=> true - * ``` - * - * @param {Object} `config` If supplied, this object is passed to [cache-base][] to merge onto the the instance upon instantiation. - * @param {Object} `options` If supplied, this object is used to initialize the `base.options` object. - * @api public - */ - - function Base(config, options) { - if (!(this instanceof Base)) { - return new Base(config, options); - } - Cache.call(this, config); - this.is('base'); - this.initBase(config, options); - } - - /** - * Inherit cache-base - */ - - util.inherits(Base, Cache); - - /** - * Add static emitter methods - */ - - Emitter(Base); - - /** - * Initialize `Base` defaults with the given `config` object - */ - - Base.prototype.initBase = function(config, options) { - this.options = merge({}, this.options, options); - this.cache = this.cache || {}; - this.define('registered', {}); - if (name) this[name] = {}; - - // make `app._callbacks` non-enumerable - this.define('_callbacks', this._callbacks); - if (isObject(config)) { - this.visit('set', config); - } - Base.run(this, 'use', fns); - }; - - /** - * Set the given `name` on `app._name` and `app.is*` properties. Used for doing - * lookups in plugins. - * - * ```js - * app.is('foo'); - * console.log(app._name); - * //=> 'foo' - * console.log(app.isFoo); - * //=> true - * app.is('bar'); - * console.log(app.isFoo); - * //=> true - * console.log(app.isBar); - * //=> true - * console.log(app._name); - * //=> 'bar' - * ``` - * @name .is - * @param {String} `name` - * @return {Boolean} - * @api public - */ - - Base.prototype.is = function(name) { - if (typeof name !== 'string') { - throw new TypeError('expected name to be a string'); - } - this.define('is' + pascal(name), true); - this.define('_name', name); - this.define('_appname', name); - return this; - }; - - /** - * Returns true if a plugin has already been registered on an instance. - * - * Plugin implementors are encouraged to use this first thing in a plugin - * to prevent the plugin from being called more than once on the same - * instance. - * - * ```js - * var base = new Base(); - * base.use(function(app) { - * if (app.isRegistered('myPlugin')) return; - * // do stuff to `app` - * }); - * - * // to also record the plugin as being registered - * base.use(function(app) { - * if (app.isRegistered('myPlugin', true)) return; - * // do stuff to `app` - * }); - * ``` - * @name .isRegistered - * @emits `plugin` Emits the name of the plugin being registered. Useful for unit tests, to ensure plugins are only registered once. - * @param {String} `name` The plugin name. - * @param {Boolean} `register` If the plugin if not already registered, to record it as being registered pass `true` as the second argument. - * @return {Boolean} Returns true if a plugin is already registered. - * @api public - */ - - Base.prototype.isRegistered = function(name, register) { - if (this.registered.hasOwnProperty(name)) { - return true; - } - if (register !== false) { - this.registered[name] = true; - this.emit('plugin', name); - } - return false; - }; - - /** - * Define a plugin function to be called immediately upon init. Plugins are chainable - * and expose the following arguments to the plugin function: - * - * - `app`: the current instance of `Base` - * - `base`: the [first ancestor instance](#base) of `Base` - * - * ```js - * var app = new Base() - * .use(foo) - * .use(bar) - * .use(baz) - * ``` - * @name .use - * @param {Function} `fn` plugin function to call - * @return {Object} Returns the item instance for chaining. - * @api public - */ - - Base.prototype.use = function(fn) { - fn.call(this, this); - return this; - }; - - /** - * The `.define` method is used for adding non-enumerable property on the instance. - * Dot-notation is **not supported** with `define`. - * - * ```js - * // arbitrary `render` function using lodash `template` - * app.define('render', function(str, locals) { - * return _.template(str)(locals); - * }); - * ``` - * @name .define - * @param {String} `key` The name of the property to define. - * @param {any} `value` - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Base.prototype.define = function(key, val) { - if (isObject(key)) { - return this.visit('define', key); - } - define(this, key, val); - return this; - }; - - /** - * Mix property `key` onto the Base prototype. If base is inherited using - * `Base.extend` this method will be overridden by a new `mixin` method that will - * only add properties to the prototype of the inheriting application. - * - * ```js - * app.mixin('foo', function() { - * // do stuff - * }); - * ``` - * @name .mixin - * @param {String} `key` - * @param {Object|Array} `val` - * @return {Object} Returns the `base` instance for chaining. - * @api public - */ - - Base.prototype.mixin = function(key, val) { - Base.prototype[key] = val; - return this; - }; - - /** - * Non-enumberable mixin array, used by the static [Base.mixin]() method. - */ - - Base.prototype.mixins = Base.prototype.mixins || []; - - /** - * Getter/setter used when creating nested instances of `Base`, for storing a reference - * to the first ancestor instance. This works by setting an instance of `Base` on the `parent` - * property of a "child" instance. The `base` property defaults to the current instance if - * no `parent` property is defined. - * - * ```js - * // create an instance of `Base`, this is our first ("base") instance - * var first = new Base(); - * first.foo = 'bar'; // arbitrary property, to make it easier to see what's happening later - * - * // create another instance - * var second = new Base(); - * // create a reference to the first instance (`first`) - * second.parent = first; - * - * // create another instance - * var third = new Base(); - * // create a reference to the previous instance (`second`) - * // repeat this pattern every time a "child" instance is created - * third.parent = second; - * - * // we can always access the first instance using the `base` property - * console.log(first.base.foo); - * //=> 'bar' - * console.log(second.base.foo); - * //=> 'bar' - * console.log(third.base.foo); - * //=> 'bar' - * // and now you know how to get to third base ;) - * ``` - * @name .base - * @api public - */ - - Object.defineProperty(Base.prototype, 'base', { - configurable: true, - get: function() { - return this.parent ? this.parent.base : this; - } - }); - - /** - * Static method for adding global plugin functions that will - * be added to an instance when created. - * - * ```js - * Base.use(function(app) { - * app.foo = 'bar'; - * }); - * var app = new Base(); - * console.log(app.foo); - * //=> 'bar' - * ``` - * @name #use - * @param {Function} `fn` Plugin function to use on each instance. - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'use', function(fn) { - fns.push(fn); - return Base; - }); - - /** - * Run an array of functions by passing each function - * to a method on the given object specified by the given property. - * - * @param {Object} `obj` Object containing method to use. - * @param {String} `prop` Name of the method on the object to use. - * @param {Array} `arr` Array of functions to pass to the method. - */ - - define(Base, 'run', function(obj, prop, arr) { - var len = arr.length, i = 0; - while (len--) { - obj[prop](arr[i++]); - } - return Base; - }); - - /** - * Static method for inheriting the prototype and static methods of the `Base` class. - * This method greatly simplifies the process of creating inheritance-based applications. - * See [static-extend][] for more details. - * - * ```js - * var extend = cu.extend(Parent); - * Parent.extend(Child); - * - * // optional methods - * Parent.extend(Child, { - * foo: function() {}, - * bar: function() {} - * }); - * ``` - * @name #extend - * @param {Function} `Ctor` constructor to extend - * @param {Object} `methods` Optional prototype properties to mix in. - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'extend', cu.extend(Base, function(Ctor, Parent) { - Ctor.prototype.mixins = Ctor.prototype.mixins || []; - - define(Ctor, 'mixin', function(fn) { - var mixin = fn(Ctor.prototype, Ctor); - if (typeof mixin === 'function') { - Ctor.prototype.mixins.push(mixin); - } - return Ctor; - }); - - define(Ctor, 'mixins', function(Child) { - Base.run(Child, 'mixin', Ctor.prototype.mixins); - return Ctor; - }); - - Ctor.prototype.mixin = function(key, value) { - Ctor.prototype[key] = value; - return this; - }; - return Base; - })); - - /** - * Used for adding methods to the `Base` prototype, and/or to the prototype of child instances. - * When a mixin function returns a function, the returned function is pushed onto the `.mixins` - * array, making it available to be used on inheriting classes whenever `Base.mixins()` is - * called (e.g. `Base.mixins(Child)`). - * - * ```js - * Base.mixin(function(proto) { - * proto.foo = function(msg) { - * return 'foo ' + msg; - * }; - * }); - * ``` - * @name #mixin - * @param {Function} `fn` Function to call - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'mixin', function(fn) { - var mixin = fn(Base.prototype, Base); - if (typeof mixin === 'function') { - Base.prototype.mixins.push(mixin); - } - return Base; - }); - - /** - * Static method for running global mixin functions against a child constructor. - * Mixins must be registered before calling this method. - * - * ```js - * Base.extend(Child); - * Base.mixins(Child); - * ``` - * @name #mixins - * @param {Function} `Child` Constructor function of a child class - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'mixins', function(Child) { - Base.run(Child, 'mixin', Base.prototype.mixins); - return Base; - }); - - /** - * Similar to `util.inherit`, but copies all static properties, prototype properties, and - * getters/setters from `Provider` to `Receiver`. See [class-utils][]{#inherit} for more details. - * - * ```js - * Base.inherit(Foo, Bar); - * ``` - * @name #inherit - * @param {Function} `Receiver` Receiving (child) constructor - * @param {Function} `Provider` Providing (parent) constructor - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'inherit', cu.inherit); - define(Base, 'bubble', cu.bubble); - return Base; -} - -/** - * Expose `Base` with default settings - */ - -module.exports = namespace(); - -/** - * Allow users to define a namespace - */ - -module.exports.namespace = namespace; - - -/***/ }), -/* 770 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isDescriptor = __webpack_require__(760); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } - - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; - - -/***/ }), -/* 771 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(748); -var Emitter = __webpack_require__(772); -var visit = __webpack_require__(773); -var toPath = __webpack_require__(776); -var union = __webpack_require__(777); -var del = __webpack_require__(781); -var get = __webpack_require__(779); -var has = __webpack_require__(786); -var set = __webpack_require__(780); - -/** - * Create a `Cache` constructor that when instantiated will - * store values on the given `prop`. - * - * ```js - * var Cache = require('cache-base').namespace('data'); - * var cache = new Cache(); - * - * cache.set('foo', 'bar'); - * //=> {data: {foo: 'bar'}} - * ``` - * @param {String} `prop` The property name to use for storing values. - * @return {Function} Returns a custom `Cache` constructor - * @api public - */ - -function namespace(prop) { - - /** - * Create a new `Cache`. Internally the `Cache` constructor is created using - * the `namespace` function, with `cache` defined as the storage object. - * - * ```js - * var app = new Cache(); - * ``` - * @param {Object} `cache` Optionally pass an object to initialize with. - * @constructor - * @api public - */ - - function Cache(cache) { - if (prop) { - this[prop] = {}; - } - if (cache) { - this.set(cache); - } - } - - /** - * Inherit Emitter - */ - - Emitter(Cache.prototype); - - /** - * Assign `value` to `key`. Also emits `set` with - * the key and value. - * - * ```js - * app.on('set', function(key, val) { - * // do something when `set` is emitted - * }); - * - * app.set(key, value); - * - * // also takes an object or array - * app.set({name: 'Halle'}); - * app.set([{foo: 'bar'}, {baz: 'quux'}]); - * console.log(app); - * //=> {name: 'Halle', foo: 'bar', baz: 'quux'} - * ``` - * - * @name .set - * @emits `set` with `key` and `value` as arguments. - * @param {String} `key` - * @param {any} `value` - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Cache.prototype.set = function(key, val) { - if (Array.isArray(key) && arguments.length === 2) { - key = toPath(key); - } - if (isObject(key) || Array.isArray(key)) { - this.visit('set', key); - } else { - set(prop ? this[prop] : this, key, val); - this.emit('set', key, val); - } - return this; - }; - - /** - * Union `array` to `key`. Also emits `set` with - * the key and value. - * - * ```js - * app.union('a.b', ['foo']); - * app.union('a.b', ['bar']); - * console.log(app.get('a')); - * //=> {b: ['foo', 'bar']} - * ``` - * @name .union - * @param {String} `key` - * @param {any} `value` - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Cache.prototype.union = function(key, val) { - if (Array.isArray(key) && arguments.length === 2) { - key = toPath(key); - } - var ctx = prop ? this[prop] : this; - union(ctx, key, arrayify(val)); - this.emit('union', val); - return this; - }; - - /** - * Return the value of `key`. Dot notation may be used - * to get [nested property values][get-value]. - * - * ```js - * app.set('a.b.c', 'd'); - * app.get('a.b'); - * //=> {c: 'd'} - * - * app.get(['a', 'b']); - * //=> {c: 'd'} - * ``` - * - * @name .get - * @emits `get` with `key` and `value` as arguments. - * @param {String} `key` The name of the property to get. Dot-notation may be used. - * @return {any} Returns the value of `key` - * @api public - */ - - Cache.prototype.get = function(key) { - key = toPath(arguments); - - var ctx = prop ? this[prop] : this; - var val = get(ctx, key); - - this.emit('get', key, val); - return val; - }; - - /** - * Return true if app has a stored value for `key`, - * false only if value is `undefined`. - * - * ```js - * app.set('foo', 'bar'); - * app.has('foo'); - * //=> true - * ``` - * - * @name .has - * @emits `has` with `key` and true or false as arguments. - * @param {String} `key` - * @return {Boolean} - * @api public - */ - - Cache.prototype.has = function(key) { - key = toPath(arguments); - - var ctx = prop ? this[prop] : this; - var val = get(ctx, key); - - var has = typeof val !== 'undefined'; - this.emit('has', key, has); - return has; - }; - - /** - * Delete one or more properties from the instance. - * - * ```js - * app.del(); // delete all - * // or - * app.del('foo'); - * // or - * app.del(['foo', 'bar']); - * ``` - * @name .del - * @emits `del` with the `key` as the only argument. - * @param {String|Array} `key` Property name or array of property names. - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Cache.prototype.del = function(key) { - if (Array.isArray(key)) { - this.visit('del', key); - } else { - del(prop ? this[prop] : this, key); - this.emit('del', key); - } - return this; - }; - - /** - * Reset the entire cache to an empty object. - * - * ```js - * app.clear(); - * ``` - * @api public - */ - - Cache.prototype.clear = function() { - if (prop) { - this[prop] = {}; - } - }; - - /** - * Visit `method` over the properties in the given object, or map - * visit over the object-elements in an array. - * - * @name .visit - * @param {String} `method` The name of the `base` method to call. - * @param {Object|Array} `val` The object or array to iterate over. - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Cache.prototype.visit = function(method, val) { - visit(this, method, val); - return this; - }; - - return Cache; -} - -/** - * Cast val to an array - */ - -function arrayify(val) { - return val ? (Array.isArray(val) ? val : [val]) : []; -} - -/** - * Expose `Cache` - */ - -module.exports = namespace(); - -/** - * Expose `Cache.namespace` - */ - -module.exports.namespace = namespace; - - -/***/ }), -/* 772 */ -/***/ (function(module, exports, __webpack_require__) { - - -/** - * Expose `Emitter`. - */ - -if (true) { - module.exports = Emitter; -} - -/** - * Initialize a new `Emitter`. - * - * @api public - */ - -function Emitter(obj) { - if (obj) return mixin(obj); -}; - -/** - * Mixin the emitter properties. - * - * @param {Object} obj - * @return {Object} - * @api private - */ - -function mixin(obj) { - for (var key in Emitter.prototype) { - obj[key] = Emitter.prototype[key]; - } - return obj; -} - -/** - * Listen on the given `event` with `fn`. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.on = -Emitter.prototype.addEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - (this._callbacks['$' + event] = this._callbacks['$' + event] || []) - .push(fn); - return this; -}; - -/** - * Adds an `event` listener that will be invoked a single - * time then automatically removed. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.once = function(event, fn){ - function on() { - this.off(event, on); - fn.apply(this, arguments); - } - - on.fn = fn; - this.on(event, on); - return this; -}; - -/** - * Remove the given callback for `event` or all - * registered callbacks. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.off = -Emitter.prototype.removeListener = -Emitter.prototype.removeAllListeners = -Emitter.prototype.removeEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - - // all - if (0 == arguments.length) { - this._callbacks = {}; - return this; - } - - // specific event - var callbacks = this._callbacks['$' + event]; - if (!callbacks) return this; - - // remove all handlers - if (1 == arguments.length) { - delete this._callbacks['$' + event]; - return this; - } - - // remove specific handler - var cb; - for (var i = 0; i < callbacks.length; i++) { - cb = callbacks[i]; - if (cb === fn || cb.fn === fn) { - callbacks.splice(i, 1); - break; - } - } - return this; -}; - -/** - * Emit `event` with the given args. - * - * @param {String} event - * @param {Mixed} ... - * @return {Emitter} - */ - -Emitter.prototype.emit = function(event){ - this._callbacks = this._callbacks || {}; - var args = [].slice.call(arguments, 1) - , callbacks = this._callbacks['$' + event]; - - if (callbacks) { - callbacks = callbacks.slice(0); - for (var i = 0, len = callbacks.length; i < len; ++i) { - callbacks[i].apply(this, args); - } - } - - return this; -}; - -/** - * Return array of callbacks for `event`. - * - * @param {String} event - * @return {Array} - * @api public - */ - -Emitter.prototype.listeners = function(event){ - this._callbacks = this._callbacks || {}; - return this._callbacks['$' + event] || []; -}; - -/** - * Check if this emitter has `event` handlers. - * - * @param {String} event - * @return {Boolean} - * @api public - */ - -Emitter.prototype.hasListeners = function(event){ - return !! this.listeners(event).length; -}; - - -/***/ }), -/* 773 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * collection-visit - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var visit = __webpack_require__(774); -var mapVisit = __webpack_require__(775); - -module.exports = function(collection, method, val) { - var result; - - if (typeof val === 'string' && (method in collection)) { - var args = [].slice.call(arguments, 2); - result = collection[method].apply(collection, args); - } else if (Array.isArray(val)) { - result = mapVisit.apply(null, arguments); - } else { - result = visit.apply(null, arguments); - } - - if (typeof result !== 'undefined') { - return result; - } - - return collection; -}; - - -/***/ }), -/* 774 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * object-visit - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isObject = __webpack_require__(748); - -module.exports = function visit(thisArg, method, target, val) { - if (!isObject(thisArg) && typeof thisArg !== 'function') { - throw new Error('object-visit expects `thisArg` to be an object.'); - } - - if (typeof method !== 'string') { - throw new Error('object-visit expects `method` name to be a string'); - } - - if (typeof thisArg[method] !== 'function') { - return thisArg; - } - - var args = [].slice.call(arguments, 3); - target = target || {}; - - for (var key in target) { - var arr = [key, target[key]].concat(args); - thisArg[method].apply(thisArg, arr); - } - return thisArg; -}; - - -/***/ }), -/* 775 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var util = __webpack_require__(29); -var visit = __webpack_require__(774); - -/** - * Map `visit` over an array of objects. - * - * @param {Object} `collection` The context in which to invoke `method` - * @param {String} `method` Name of the method to call on `collection` - * @param {Object} `arr` Array of objects. - */ - -module.exports = function mapVisit(collection, method, val) { - if (isObject(val)) { - return visit.apply(null, arguments); - } - - if (!Array.isArray(val)) { - throw new TypeError('expected an array: ' + util.inspect(val)); - } - - var args = [].slice.call(arguments, 3); - - for (var i = 0; i < val.length; i++) { - var ele = val[i]; - if (isObject(ele)) { - visit.apply(null, [collection, method, ele].concat(args)); - } else { - collection[method].apply(collection, [ele].concat(args)); - } - } -}; - -function isObject(val) { - return val && (typeof val === 'function' || (!Array.isArray(val) && typeof val === 'object')); -} - - -/***/ }), -/* 776 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * to-object-path - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var typeOf = __webpack_require__(753); - -module.exports = function toPath(args) { - if (typeOf(args) !== 'arguments') { - args = arguments; - } - return filter(args).join('.'); -}; - -function filter(arr) { - var len = arr.length; - var idx = -1; - var res = []; - - while (++idx < len) { - var ele = arr[idx]; - if (typeOf(ele) === 'arguments' || Array.isArray(ele)) { - res.push.apply(res, filter(ele)); - } else if (typeof ele === 'string') { - res.push(ele); - } - } - return res; -} - - -/***/ }), -/* 777 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(739); -var union = __webpack_require__(778); -var get = __webpack_require__(779); -var set = __webpack_require__(780); - -module.exports = function unionValue(obj, prop, value) { - if (!isObject(obj)) { - throw new TypeError('union-value expects the first argument to be an object.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('union-value expects `prop` to be a string.'); - } - - var arr = arrayify(get(obj, prop)); - set(obj, prop, union(arr, arrayify(value))); - return obj; -}; - -function arrayify(val) { - if (val === null || typeof val === 'undefined') { - return []; - } - if (Array.isArray(val)) { - return val; - } - return [val]; -} - - -/***/ }), -/* 778 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function union(init) { - if (!Array.isArray(init)) { - throw new TypeError('arr-union expects the first argument to be an array.'); - } - - var len = arguments.length; - var i = 0; - - while (++i < len) { - var arg = arguments[i]; - if (!arg) continue; - - if (!Array.isArray(arg)) { - arg = [arg]; - } - - for (var j = 0; j < arg.length; j++) { - var ele = arg[j]; - - if (init.indexOf(ele) >= 0) { - continue; - } - init.push(ele); - } - } - return init; -}; - - -/***/ }), -/* 779 */ -/***/ (function(module, exports) { - -/*! - * get-value - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -module.exports = function(obj, prop, a, b, c) { - if (!isObject(obj) || !prop) { - return obj; - } - - prop = toString(prop); - - // allowing for multiple properties to be passed as - // a string or array, but much faster (3-4x) than doing - // `[].slice.call(arguments)` - if (a) prop += '.' + toString(a); - if (b) prop += '.' + toString(b); - if (c) prop += '.' + toString(c); - - if (prop in obj) { - return obj[prop]; - } - - var segs = prop.split('.'); - var len = segs.length; - var i = -1; - - while (obj && (++i < len)) { - var key = segs[i]; - while (key[key.length - 1] === '\\') { - key = key.slice(0, -1) + '.' + segs[++i]; - } - obj = obj[key]; - } - return obj; -}; - -function isObject(val) { - return val !== null && (typeof val === 'object' || typeof val === 'function'); -} - -function toString(val) { - if (!val) return ''; - if (Array.isArray(val)) { - return val.join('.'); - } - return val; -} - - -/***/ }), -/* 780 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * set-value - * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var split = __webpack_require__(744); -var extend = __webpack_require__(738); -var isPlainObject = __webpack_require__(747); -var isObject = __webpack_require__(739); - -module.exports = function(obj, prop, val) { - if (!isObject(obj)) { - return obj; - } - - if (Array.isArray(prop)) { - prop = [].concat.apply([], prop).join('.'); - } - - if (typeof prop !== 'string') { - return obj; - } - - var keys = split(prop, {sep: '.', brackets: true}).filter(isValidKey); - var len = keys.length; - var idx = -1; - var current = obj; - - while (++idx < len) { - var key = keys[idx]; - if (idx !== len - 1) { - if (!isObject(current[key])) { - current[key] = {}; - } - current = current[key]; - continue; - } - - if (isPlainObject(current[key]) && isPlainObject(val)) { - current[key] = extend({}, current[key], val); - } else { - current[key] = val; - } - } - - return obj; -}; - -function isValidKey(key) { - return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; -} - - -/***/ }), -/* 781 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * unset-value - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isObject = __webpack_require__(748); -var has = __webpack_require__(782); - -module.exports = function unset(obj, prop) { - if (!isObject(obj)) { - throw new TypeError('expected an object.'); - } - if (obj.hasOwnProperty(prop)) { - delete obj[prop]; - return true; - } - - if (has(obj, prop)) { - var segs = prop.split('.'); - var last = segs.pop(); - while (segs.length && segs[segs.length - 1].slice(-1) === '\\') { - last = segs.pop().slice(0, -1) + '.' + last; - } - while (segs.length) obj = obj[prop = segs.shift()]; - return (delete obj[last]); - } - return true; -}; - - -/***/ }), -/* 782 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-value - * - * Copyright (c) 2014-2016, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var isObject = __webpack_require__(783); -var hasValues = __webpack_require__(785); -var get = __webpack_require__(779); - -module.exports = function(obj, prop, noZero) { - if (isObject(obj)) { - return hasValues(get(obj, prop), noZero); - } - return hasValues(obj, prop); -}; - - -/***/ }), -/* 783 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * isobject - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var isArray = __webpack_require__(784); - -module.exports = function isObject(val) { - return val != null && typeof val === 'object' && isArray(val) === false; -}; - - -/***/ }), -/* 784 */ -/***/ (function(module, exports) { - -var toString = {}.toString; - -module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; -}; - - -/***/ }), -/* 785 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-values - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -module.exports = function hasValue(o, noZero) { - if (o === null || o === undefined) { - return false; - } - - if (typeof o === 'boolean') { - return true; - } - - if (typeof o === 'number') { - if (o === 0 && noZero === true) { - return false; - } - return true; - } - - if (o.length !== undefined) { - return o.length !== 0; - } - - for (var key in o) { - if (o.hasOwnProperty(key)) { - return true; - } - } - return false; -}; - - -/***/ }), -/* 786 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-value - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var isObject = __webpack_require__(748); -var hasValues = __webpack_require__(787); -var get = __webpack_require__(779); - -module.exports = function(val, prop) { - return hasValues(isObject(val) && prop ? get(val, prop) : val); -}; - - -/***/ }), -/* 787 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-values - * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var typeOf = __webpack_require__(788); -var isNumber = __webpack_require__(752); - -module.exports = function hasValue(val) { - // is-number checks for NaN and other edge cases - if (isNumber(val)) { - return true; - } - - switch (typeOf(val)) { - case 'null': - case 'boolean': - case 'function': - return true; - case 'string': - case 'arguments': - return val.length !== 0; - case 'error': - return val.message !== ''; - case 'array': - var len = val.length; - if (len === 0) { - return false; - } - for (var i = 0; i < len; i++) { - if (hasValue(val[i])) { - return true; - } - } - return false; - case 'file': - case 'map': - case 'set': - return val.size !== 0; - case 'object': - var keys = Object.keys(val); - if (keys.length === 0) { - return false; - } - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - if (hasValue(val[key])) { - return true; - } - } - return false; - default: { - return false; - } - } -}; - - -/***/ }), -/* 788 */ -/***/ (function(module, exports, __webpack_require__) { - -var isBuffer = __webpack_require__(735); -var toString = Object.prototype.toString; - -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ - -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } - - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } - - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } - - // other objects - var type = toString.call(val); - - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - if (type === '[object Promise]') { - return 'promise'; - } - - // buffer - if (isBuffer(val)) { - return 'buffer'; - } - - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } - - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } - - // must be a plain object - return 'object'; -}; - - -/***/ }), -/* 789 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isExtendable = __webpack_require__(790); -var forIn = __webpack_require__(791); - -function mixinDeep(target, objects) { - var len = arguments.length, i = 0; - while (++i < len) { - var obj = arguments[i]; - if (isObject(obj)) { - forIn(obj, copy, target); - } - } - return target; -} - -/** - * Copy properties from the source object to the - * target object. - * - * @param {*} `val` - * @param {String} `key` - */ - -function copy(val, key) { - if (!isValidKey(key)) { - return; - } - - var obj = this[key]; - if (isObject(val) && isObject(obj)) { - mixinDeep(obj, val); - } else { - this[key] = val; - } -} - -/** - * Returns true if `val` is an object or function. - * - * @param {any} val - * @return {Boolean} - */ - -function isObject(val) { - return isExtendable(val) && !Array.isArray(val); -} - -/** - * Returns true if `key` is a valid key to use when extending objects. - * - * @param {String} `key` - * @return {Boolean} - */ - -function isValidKey(key) { - return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; -}; - -/** - * Expose `mixinDeep` - */ - -module.exports = mixinDeep; - - -/***/ }), -/* 790 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isPlainObject = __webpack_require__(747); - -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); -}; - - -/***/ }), -/* 791 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * for-in - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function forIn(obj, fn, thisArg) { - for (var key in obj) { - if (fn.call(thisArg, obj[key], key, obj) === false) { - break; - } - } -}; - - -/***/ }), -/* 792 */ -/***/ (function(module, exports) { - -/*! - * pascalcase - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -function pascalcase(str) { - if (typeof str !== 'string') { - throw new TypeError('expected a string.'); - } - str = str.replace(/([A-Z])/g, ' $1'); - if (str.length === 1) { return str.toUpperCase(); } - str = str.replace(/^[\W_]+|[\W_]+$/g, '').toLowerCase(); - str = str.charAt(0).toUpperCase() + str.slice(1); - return str.replace(/[\W_]+(\w|$)/g, function (_, ch) { - return ch.toUpperCase(); - }); -} - -module.exports = pascalcase; - - -/***/ }), -/* 793 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var util = __webpack_require__(29); -var utils = __webpack_require__(794); - -/** - * Expose class utils - */ - -var cu = module.exports; - -/** - * Expose class utils: `cu` - */ - -cu.isObject = function isObject(val) { - return utils.isObj(val) || typeof val === 'function'; -}; - -/** - * Returns true if an array has any of the given elements, or an - * object has any of the give keys. - * - * ```js - * cu.has(['a', 'b', 'c'], 'c'); - * //=> true - * - * cu.has(['a', 'b', 'c'], ['c', 'z']); - * //=> true - * - * cu.has({a: 'b', c: 'd'}, ['c', 'z']); - * //=> true - * ``` - * @param {Object} `obj` - * @param {String|Array} `val` - * @return {Boolean} - * @api public - */ - -cu.has = function has(obj, val) { - val = cu.arrayify(val); - var len = val.length; - - if (cu.isObject(obj)) { - for (var key in obj) { - if (val.indexOf(key) > -1) { - return true; - } - } - - var keys = cu.nativeKeys(obj); - return cu.has(keys, val); - } - - if (Array.isArray(obj)) { - var arr = obj; - while (len--) { - if (arr.indexOf(val[len]) > -1) { - return true; - } - } - return false; - } - - throw new TypeError('expected an array or object.'); -}; - -/** - * Returns true if an array or object has all of the given values. - * - * ```js - * cu.hasAll(['a', 'b', 'c'], 'c'); - * //=> true - * - * cu.hasAll(['a', 'b', 'c'], ['c', 'z']); - * //=> false - * - * cu.hasAll({a: 'b', c: 'd'}, ['c', 'z']); - * //=> false - * ``` - * @param {Object|Array} `val` - * @param {String|Array} `values` - * @return {Boolean} - * @api public - */ - -cu.hasAll = function hasAll(val, values) { - values = cu.arrayify(values); - var len = values.length; - while (len--) { - if (!cu.has(val, values[len])) { - return false; - } - } - return true; -}; - -/** - * Cast the given value to an array. - * - * ```js - * cu.arrayify('foo'); - * //=> ['foo'] - * - * cu.arrayify(['foo']); - * //=> ['foo'] - * ``` - * - * @param {String|Array} `val` - * @return {Array} - * @api public - */ - -cu.arrayify = function arrayify(val) { - return val ? (Array.isArray(val) ? val : [val]) : []; -}; - -/** - * Noop - */ - -cu.noop = function noop() { - return; -}; - -/** - * Returns the first argument passed to the function. - */ - -cu.identity = function identity(val) { - return val; -}; - -/** - * Returns true if a value has a `contructor` - * - * ```js - * cu.hasConstructor({}); - * //=> true - * - * cu.hasConstructor(Object.create(null)); - * //=> false - * ``` - * @param {Object} `value` - * @return {Boolean} - * @api public - */ - -cu.hasConstructor = function hasConstructor(val) { - return cu.isObject(val) && typeof val.constructor !== 'undefined'; -}; - -/** - * Get the native `ownPropertyNames` from the constructor of the - * given `object`. An empty array is returned if the object does - * not have a constructor. - * - * ```js - * cu.nativeKeys({a: 'b', b: 'c', c: 'd'}) - * //=> ['a', 'b', 'c'] - * - * cu.nativeKeys(function(){}) - * //=> ['length', 'caller'] - * ``` - * - * @param {Object} `obj` Object that has a `constructor`. - * @return {Array} Array of keys. - * @api public - */ - -cu.nativeKeys = function nativeKeys(val) { - if (!cu.hasConstructor(val)) return []; - return Object.getOwnPropertyNames(val); -}; - -/** - * Returns property descriptor `key` if it's an "own" property - * of the given object. - * - * ```js - * function App() {} - * Object.defineProperty(App.prototype, 'count', { - * get: function() { - * return Object.keys(this).length; - * } - * }); - * cu.getDescriptor(App.prototype, 'count'); - * // returns: - * // { - * // get: [Function], - * // set: undefined, - * // enumerable: false, - * // configurable: false - * // } - * ``` - * - * @param {Object} `obj` - * @param {String} `key` - * @return {Object} Returns descriptor `key` - * @api public - */ - -cu.getDescriptor = function getDescriptor(obj, key) { - if (!cu.isObject(obj)) { - throw new TypeError('expected an object.'); - } - if (typeof key !== 'string') { - throw new TypeError('expected key to be a string.'); - } - return Object.getOwnPropertyDescriptor(obj, key); -}; - -/** - * Copy a descriptor from one object to another. - * - * ```js - * function App() {} - * Object.defineProperty(App.prototype, 'count', { - * get: function() { - * return Object.keys(this).length; - * } - * }); - * var obj = {}; - * cu.copyDescriptor(obj, App.prototype, 'count'); - * ``` - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String} `name` - * @return {Object} - * @api public - */ - -cu.copyDescriptor = function copyDescriptor(receiver, provider, name) { - if (!cu.isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!cu.isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } - if (typeof name !== 'string') { - throw new TypeError('expected name to be a string.'); - } - - var val = cu.getDescriptor(provider, name); - if (val) Object.defineProperty(receiver, name, val); -}; - -/** - * Copy static properties, prototype properties, and descriptors - * from one object to another. - * - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String|Array} `omit` One or more properties to omit - * @return {Object} - * @api public - */ - -cu.copy = function copy(receiver, provider, omit) { - if (!cu.isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!cu.isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } - var props = Object.getOwnPropertyNames(provider); - var keys = Object.keys(provider); - var len = props.length, - key; - omit = cu.arrayify(omit); - - while (len--) { - key = props[len]; - - if (cu.has(keys, key)) { - utils.define(receiver, key, provider[key]); - } else if (!(key in receiver) && !cu.has(omit, key)) { - cu.copyDescriptor(receiver, provider, key); - } - } -}; - -/** - * Inherit the static properties, prototype properties, and descriptors - * from of an object. - * - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String|Array} `omit` One or more properties to omit - * @return {Object} - * @api public - */ - -cu.inherit = function inherit(receiver, provider, omit) { - if (!cu.isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!cu.isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } - - var keys = []; - for (var key in provider) { - keys.push(key); - receiver[key] = provider[key]; - } - - keys = keys.concat(cu.arrayify(omit)); - - var a = provider.prototype || provider; - var b = receiver.prototype || receiver; - cu.copy(b, a, keys); -}; - -/** - * Returns a function for extending the static properties, - * prototype properties, and descriptors from the `Parent` - * constructor onto `Child` constructors. - * - * ```js - * var extend = cu.extend(Parent); - * Parent.extend(Child); - * - * // optional methods - * Parent.extend(Child, { - * foo: function() {}, - * bar: function() {} - * }); - * ``` - * @param {Function} `Parent` Parent ctor - * @param {Function} `extend` Optional extend function to handle custom extensions. Useful when updating methods that require a specific prototype. - * @param {Function} `Child` Child ctor - * @param {Object} `proto` Optionally pass additional prototype properties to inherit. - * @return {Object} - * @api public - */ - -cu.extend = function() { - // keep it lazy, instead of assigning to `cu.extend` - return utils.staticExtend.apply(null, arguments); -}; - -/** - * Bubble up events emitted from static methods on the Parent ctor. - * - * @param {Object} `Parent` - * @param {Array} `events` Event names to bubble up - * @api public - */ - -cu.bubble = function(Parent, events) { - events = events || []; - Parent.bubble = function(Child, arr) { - if (Array.isArray(arr)) { - events = utils.union([], events, arr); - } - var len = events.length; - var idx = -1; - while (++idx < len) { - var name = events[idx]; - Parent.on(name, Child.emit.bind(Child, name)); - } - cu.bubble(Child, events); - }; -}; - - -/***/ }), -/* 794 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = {}; - - - -/** - * Lazily required module dependencies - */ - -utils.union = __webpack_require__(778); -utils.define = __webpack_require__(730); -utils.isObj = __webpack_require__(748); -utils.staticExtend = __webpack_require__(795); - - -/** - * Expose `utils` - */ - -module.exports = utils; - - -/***/ }), -/* 795 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * static-extend - * - * Copyright (c) 2016, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var copy = __webpack_require__(796); -var define = __webpack_require__(730); -var util = __webpack_require__(29); - -/** - * Returns a function for extending the static properties, - * prototype properties, and descriptors from the `Parent` - * constructor onto `Child` constructors. - * - * ```js - * var extend = require('static-extend'); - * Parent.extend = extend(Parent); - * - * // optionally pass a custom merge function as the second arg - * Parent.extend = extend(Parent, function(Child) { - * Child.prototype.mixin = function(key, val) { - * Child.prototype[key] = val; - * }; - * }); - * - * // extend "child" constructors - * Parent.extend(Child); - * - * // optionally define prototype methods as the second arg - * Parent.extend(Child, { - * foo: function() {}, - * bar: function() {} - * }); - * ``` - * @param {Function} `Parent` Parent ctor - * @param {Function} `extendFn` Optional extend function for handling any necessary custom merging. Useful when updating methods that require a specific prototype. - * @param {Function} `Child` Child ctor - * @param {Object} `proto` Optionally pass additional prototype properties to inherit. - * @return {Object} - * @api public - */ - -function extend(Parent, extendFn) { - if (typeof Parent !== 'function') { - throw new TypeError('expected Parent to be a function.'); - } - - return function(Ctor, proto) { - if (typeof Ctor !== 'function') { - throw new TypeError('expected Ctor to be a function.'); - } - - util.inherits(Ctor, Parent); - copy(Ctor, Parent); - - // proto can be null or a plain object - if (typeof proto === 'object') { - var obj = Object.create(proto); - - for (var k in obj) { - Ctor.prototype[k] = obj[k]; - } - } - - // keep a reference to the parent prototype - define(Ctor.prototype, '_parent_', { - configurable: true, - set: function() {}, - get: function() { - return Parent.prototype; - } - }); - - if (typeof extendFn === 'function') { - extendFn(Ctor, Parent); - } - - Ctor.extend = extend(Ctor, extendFn); - }; -}; - -/** - * Expose `extend` - */ - -module.exports = extend; - - -/***/ }), -/* 796 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var typeOf = __webpack_require__(753); -var copyDescriptor = __webpack_require__(797); -var define = __webpack_require__(730); - -/** - * Copy static properties, prototype properties, and descriptors from one object to another. - * - * ```js - * function App() {} - * var proto = App.prototype; - * App.prototype.set = function() {}; - * App.prototype.get = function() {}; - * - * var obj = {}; - * copy(obj, proto); - * ``` - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String|Array} `omit` One or more properties to omit - * @return {Object} - * @api public - */ - -function copy(receiver, provider, omit) { - if (!isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } - - var props = nativeKeys(provider); - var keys = Object.keys(provider); - var len = props.length; - omit = arrayify(omit); - - while (len--) { - var key = props[len]; - - if (has(keys, key)) { - define(receiver, key, provider[key]); - } else if (!(key in receiver) && !has(omit, key)) { - copyDescriptor(receiver, provider, key); - } - } -}; - -/** - * Return true if the given value is an object or function - */ - -function isObject(val) { - return typeOf(val) === 'object' || typeof val === 'function'; -} - -/** - * Returns true if an array has any of the given elements, or an - * object has any of the give keys. - * - * ```js - * has(['a', 'b', 'c'], 'c'); - * //=> true - * - * has(['a', 'b', 'c'], ['c', 'z']); - * //=> true - * - * has({a: 'b', c: 'd'}, ['c', 'z']); - * //=> true - * ``` - * @param {Object} `obj` - * @param {String|Array} `val` - * @return {Boolean} - */ - -function has(obj, val) { - val = arrayify(val); - var len = val.length; - - if (isObject(obj)) { - for (var key in obj) { - if (val.indexOf(key) > -1) { - return true; - } - } - - var keys = nativeKeys(obj); - return has(keys, val); - } - - if (Array.isArray(obj)) { - var arr = obj; - while (len--) { - if (arr.indexOf(val[len]) > -1) { - return true; - } - } - return false; - } - - throw new TypeError('expected an array or object.'); -} - -/** - * Cast the given value to an array. - * - * ```js - * arrayify('foo'); - * //=> ['foo'] - * - * arrayify(['foo']); - * //=> ['foo'] - * ``` - * - * @param {String|Array} `val` - * @return {Array} - */ - -function arrayify(val) { - return val ? (Array.isArray(val) ? val : [val]) : []; -} - -/** - * Returns true if a value has a `contructor` - * - * ```js - * hasConstructor({}); - * //=> true - * - * hasConstructor(Object.create(null)); - * //=> false - * ``` - * @param {Object} `value` - * @return {Boolean} - */ - -function hasConstructor(val) { - return isObject(val) && typeof val.constructor !== 'undefined'; -} - -/** - * Get the native `ownPropertyNames` from the constructor of the - * given `object`. An empty array is returned if the object does - * not have a constructor. - * - * ```js - * nativeKeys({a: 'b', b: 'c', c: 'd'}) - * //=> ['a', 'b', 'c'] - * - * nativeKeys(function(){}) - * //=> ['length', 'caller'] - * ``` - * - * @param {Object} `obj` Object that has a `constructor`. - * @return {Array} Array of keys. - */ - -function nativeKeys(val) { - if (!hasConstructor(val)) return []; - return Object.getOwnPropertyNames(val); -} - -/** - * Expose `copy` - */ - -module.exports = copy; - -/** - * Expose `copy.has` for tests - */ - -module.exports.has = has; - - -/***/ }), -/* 797 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * copy-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -/** - * Copy a descriptor from one object to another. - * - * ```js - * function App() { - * this.cache = {}; - * } - * App.prototype.set = function(key, val) { - * this.cache[key] = val; - * return this; - * }; - * Object.defineProperty(App.prototype, 'count', { - * get: function() { - * return Object.keys(this.cache).length; - * } - * }); - * - * copy(App.prototype, 'count', 'len'); - * - * // create an instance - * var app = new App(); - * - * app.set('a', true); - * app.set('b', true); - * app.set('c', true); - * - * console.log(app.count); - * //=> 3 - * console.log(app.len); - * //=> 3 - * ``` - * @name copy - * @param {Object} `receiver` The target object - * @param {Object} `provider` The provider object - * @param {String} `from` The key to copy on provider. - * @param {String} `to` Optionally specify a new key name to use. - * @return {Object} - * @api public - */ - -module.exports = function copyDescriptor(receiver, provider, from, to) { - if (!isObject(provider) && typeof provider !== 'function') { - to = from; - from = provider; - provider = receiver; - } - if (!isObject(receiver) && typeof receiver !== 'function') { - throw new TypeError('expected the first argument to be an object'); - } - if (!isObject(provider) && typeof provider !== 'function') { - throw new TypeError('expected provider to be an object'); - } - - if (typeof to !== 'string') { - to = from; - } - if (typeof from !== 'string') { - throw new TypeError('expected key to be a string'); - } - - if (!(from in provider)) { - throw new Error('property "' + from + '" does not exist'); - } - - var val = Object.getOwnPropertyDescriptor(provider, from); - if (val) Object.defineProperty(receiver, to, val); -}; - -function isObject(val) { - return {}.toString.call(val) === '[object Object]'; -} - - - -/***/ }), -/* 798 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var use = __webpack_require__(799); -var define = __webpack_require__(730); -var debug = __webpack_require__(801)('snapdragon:compiler'); -var utils = __webpack_require__(807); - -/** - * Create a new `Compiler` with the given `options`. - * @param {Object} `options` - */ - -function Compiler(options, state) { - debug('initializing', __filename); - this.options = utils.extend({source: 'string'}, options); - this.state = state || {}; - this.compilers = {}; - this.output = ''; - this.set('eos', function(node) { - return this.emit(node.val, node); - }); - this.set('noop', function(node) { - return this.emit(node.val, node); - }); - this.set('bos', function(node) { - return this.emit(node.val, node); - }); - use(this); -} - -/** - * Prototype methods - */ - -Compiler.prototype = { - - /** - * Throw an error message with details including the cursor position. - * @param {String} `msg` Message to use in the Error. - */ - - error: function(msg, node) { - var pos = node.position || {start: {column: 0}}; - var message = this.options.source + ' column:' + pos.start.column + ': ' + msg; - - var err = new Error(message); - err.reason = msg; - err.column = pos.start.column; - err.source = this.pattern; - - if (this.options.silent) { - this.errors.push(err); - } else { - throw err; - } - }, - - /** - * Define a non-enumberable property on the `Compiler` instance. - * - * ```js - * compiler.define('foo', 'bar'); - * ``` - * @name .define - * @param {String} `key` propery name - * @param {any} `val` property value - * @return {Object} Returns the Compiler instance for chaining. - * @api public - */ - - define: function(key, val) { - define(this, key, val); - return this; - }, - - /** - * Emit `node.val` - */ - - emit: function(str, node) { - this.output += str; - return str; - }, - - /** - * Add a compiler `fn` with the given `name` - */ - - set: function(name, fn) { - this.compilers[name] = fn; - return this; - }, - - /** - * Get compiler `name`. - */ - - get: function(name) { - return this.compilers[name]; - }, - - /** - * Get the previous AST node. - */ - - prev: function(n) { - return this.ast.nodes[this.idx - (n || 1)] || { type: 'bos', val: '' }; - }, - - /** - * Get the next AST node. - */ - - next: function(n) { - return this.ast.nodes[this.idx + (n || 1)] || { type: 'eos', val: '' }; - }, - - /** - * Visit `node`. - */ - - visit: function(node, nodes, i) { - var fn = this.compilers[node.type]; - this.idx = i; - - if (typeof fn !== 'function') { - throw this.error('compiler "' + node.type + '" is not registered', node); - } - return fn.call(this, node, nodes, i); - }, - - /** - * Map visit over array of `nodes`. - */ - - mapVisit: function(nodes) { - if (!Array.isArray(nodes)) { - throw new TypeError('expected an array'); - } - var len = nodes.length; - var idx = -1; - while (++idx < len) { - this.visit(nodes[idx], nodes, idx); - } - return this; - }, - - /** - * Compile `ast`. - */ - - compile: function(ast, options) { - var opts = utils.extend({}, this.options, options); - this.ast = ast; - this.parsingErrors = this.ast.errors; - this.output = ''; - - // source map support - if (opts.sourcemap) { - var sourcemaps = __webpack_require__(826); - sourcemaps(this); - this.mapVisit(this.ast.nodes); - this.applySourceMaps(); - this.map = opts.sourcemap === 'generator' ? this.map : this.map.toJSON(); - return this; - } - - this.mapVisit(this.ast.nodes); - return this; - } -}; - -/** - * Expose `Compiler` - */ - -module.exports = Compiler; - - -/***/ }), -/* 799 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * use - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var utils = __webpack_require__(800); - -module.exports = function base(app, opts) { - if (!utils.isObject(app) && typeof app !== 'function') { - throw new TypeError('use: expect `app` be an object or function'); - } - - if (!utils.isObject(opts)) { - opts = {}; - } - - var prop = utils.isString(opts.prop) ? opts.prop : 'fns'; - if (!Array.isArray(app[prop])) { - utils.define(app, prop, []); - } - - /** - * Define a plugin function to be passed to use. The only - * parameter exposed to the plugin is `app`, the object or function. - * passed to `use(app)`. `app` is also exposed as `this` in plugins. - * - * Additionally, **if a plugin returns a function, the function will - * be pushed onto the `fns` array**, allowing the plugin to be - * called at a later point by the `run` method. - * - * ```js - * var use = require('use'); - * - * // define a plugin - * function foo(app) { - * // do stuff - * } - * - * var app = function(){}; - * use(app); - * - * // register plugins - * app.use(foo); - * app.use(bar); - * app.use(baz); - * ``` - * @name .use - * @param {Function} `fn` plugin function to call - * @api public - */ - - utils.define(app, 'use', use); - - /** - * Run all plugins on `fns`. Any plugin that returns a function - * when called by `use` is pushed onto the `fns` array. - * - * ```js - * var config = {}; - * app.run(config); - * ``` - * @name .run - * @param {Object} `value` Object to be modified by plugins. - * @return {Object} Returns the object passed to `run` - * @api public - */ - - utils.define(app, 'run', function(val) { - if (!utils.isObject(val)) return; - decorate(val); - - var self = this || app; - var fns = self[prop]; - var len = fns.length; - var idx = -1; - - while (++idx < len) { - val.use(fns[idx]); - } - return val; - }); - - /** - * Call plugin `fn`. If a function is returned push it into the - * `fns` array to be called by the `run` method. - */ - - function use(fn, options) { - if (typeof fn !== 'function') { - throw new TypeError('.use expects `fn` be a function'); - } - - var self = this || app; - if (typeof opts.fn === 'function') { - opts.fn.call(self, self, options); - } - - var plugin = fn.call(self, self); - if (typeof plugin === 'function') { - var fns = self[prop]; - fns.push(plugin); - } - return self; - } - - /** - * Ensure the `.use` method exists on `val` - */ - - function decorate(val) { - if (!val.use || !val.run) { - base(val); - } - } - - return app; -}; - - -/***/ }), -/* 800 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = {}; - - - -/** - * Lazily required module dependencies - */ - -utils.define = __webpack_require__(730); -utils.isObject = __webpack_require__(748); - - -utils.isString = function(val) { - return val && typeof val === 'string'; -}; - -/** - * Expose `utils` modules - */ - -module.exports = utils; - - -/***/ }), -/* 801 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * Detect Electron renderer process, which is node, but we should - * treat as a browser. - */ - -if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(802); -} else { - module.exports = __webpack_require__(805); -} - - -/***/ }), -/* 802 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * This is the web browser implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = __webpack_require__(803); -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; -exports.storage = 'undefined' != typeof chrome - && 'undefined' != typeof chrome.storage - ? chrome.storage.local - : localstorage(); - -/** - * Colors. - */ - -exports.colors = [ - 'lightseagreen', - 'forestgreen', - 'goldenrod', - 'dodgerblue', - 'darkorchid', - 'crimson' -]; - -/** - * Currently only WebKit-based Web Inspectors, Firefox >= v31, - * and the Firebug extension (any Firefox version) are known - * to support "%c" CSS customizations. - * - * TODO: add a `localStorage` variable to explicitly enable/disable colors - */ - -function useColors() { - // NB: In an Electron preload script, document will be defined but not fully - // initialized. Since we know we're in Chrome, we'll just detect this case - // explicitly - if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { - return true; - } - - // is webkit? http://stackoverflow.com/a/16459606/376773 - // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 - return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || - // is firebug? http://stackoverflow.com/a/398120/376773 - (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || - // is firefox >= v31? - // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || - // double check webkit in userAgent just in case we are in a worker - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); -} - -/** - * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. - */ - -exports.formatters.j = function(v) { - try { - return JSON.stringify(v); - } catch (err) { - return '[UnexpectedJSONParseError]: ' + err.message; - } -}; - - -/** - * Colorize log arguments if enabled. - * - * @api public - */ - -function formatArgs(args) { - var useColors = this.useColors; - - args[0] = (useColors ? '%c' : '') - + this.namespace - + (useColors ? ' %c' : ' ') - + args[0] - + (useColors ? '%c ' : ' ') - + '+' + exports.humanize(this.diff); - - if (!useColors) return; - - var c = 'color: ' + this.color; - args.splice(1, 0, c, 'color: inherit') - - // the final "%c" is somewhat tricky, because there could be other - // arguments passed either before or after the %c, so we need to - // figure out the correct index to insert the CSS into - var index = 0; - var lastC = 0; - args[0].replace(/%[a-zA-Z%]/g, function(match) { - if ('%%' === match) return; - index++; - if ('%c' === match) { - // we only are interested in the *last* %c - // (the user may have provided their own) - lastC = index; - } - }); - - args.splice(lastC, 0, c); -} - -/** - * Invokes `console.log()` when available. - * No-op when `console.log` is not a "function". - * - * @api public - */ - -function log() { - // this hackery is required for IE8/9, where - // the `console.log` function doesn't have 'apply' - return 'object' === typeof console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - try { - if (null == namespaces) { - exports.storage.removeItem('debug'); - } else { - exports.storage.debug = namespaces; - } - } catch(e) {} -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - var r; - try { - r = exports.storage.debug; - } catch(e) {} - - // If debug isn't set in LS, and we're in Electron, try to load $DEBUG - if (!r && typeof process !== 'undefined' && 'env' in process) { - r = process.env.DEBUG; - } - - return r; -} - -/** - * Enable namespaces listed in `localStorage.debug` initially. - */ - -exports.enable(load()); - -/** - * Localstorage attempts to return the localstorage. - * - * This is necessary because safari throws - * when a user disables cookies/localstorage - * and you attempt to access it. - * - * @return {LocalStorage} - * @api private - */ - -function localstorage() { - try { - return window.localStorage; - } catch (e) {} -} - - -/***/ }), -/* 803 */ -/***/ (function(module, exports, __webpack_require__) { - - -/** - * This is the common logic for both the Node.js and web browser - * implementations of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; -exports.coerce = coerce; -exports.disable = disable; -exports.enable = enable; -exports.enabled = enabled; -exports.humanize = __webpack_require__(804); - -/** - * The currently active debug mode names, and names to skip. - */ - -exports.names = []; -exports.skips = []; - -/** - * Map of special "%n" handling functions, for the debug "format" argument. - * - * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". - */ - -exports.formatters = {}; - -/** - * Previous log timestamp. - */ - -var prevTime; - -/** - * Select a color. - * @param {String} namespace - * @return {Number} - * @api private - */ - -function selectColor(namespace) { - var hash = 0, i; - - for (i in namespace) { - hash = ((hash << 5) - hash) + namespace.charCodeAt(i); - hash |= 0; // Convert to 32bit integer - } - - return exports.colors[Math.abs(hash) % exports.colors.length]; -} - -/** - * Create a debugger with the given `namespace`. - * - * @param {String} namespace - * @return {Function} - * @api public - */ - -function createDebug(namespace) { - - function debug() { - // disabled? - if (!debug.enabled) return; - - var self = debug; - - // set `diff` timestamp - var curr = +new Date(); - var ms = curr - (prevTime || curr); - self.diff = ms; - self.prev = prevTime; - self.curr = curr; - prevTime = curr; - - // turn the `arguments` into a proper Array - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } - - args[0] = exports.coerce(args[0]); - - if ('string' !== typeof args[0]) { - // anything else let's inspect with %O - args.unshift('%O'); - } - - // apply any `formatters` transformations - var index = 0; - args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { - // if we encounter an escaped % then don't increase the array index - if (match === '%%') return match; - index++; - var formatter = exports.formatters[format]; - if ('function' === typeof formatter) { - var val = args[index]; - match = formatter.call(self, val); - - // now we need to remove `args[index]` since it's inlined in the `format` - args.splice(index, 1); - index--; - } - return match; - }); - - // apply env-specific formatting (colors, etc.) - exports.formatArgs.call(self, args); - - var logFn = debug.log || exports.log || console.log.bind(console); - logFn.apply(self, args); - } - - debug.namespace = namespace; - debug.enabled = exports.enabled(namespace); - debug.useColors = exports.useColors(); - debug.color = selectColor(namespace); - - // env-specific initialization logic for debug instances - if ('function' === typeof exports.init) { - exports.init(debug); - } - - return debug; -} - -/** - * Enables a debug mode by namespaces. This can include modes - * separated by a colon and wildcards. - * - * @param {String} namespaces - * @api public - */ - -function enable(namespaces) { - exports.save(namespaces); - - exports.names = []; - exports.skips = []; - - var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - var len = split.length; - - for (var i = 0; i < len; i++) { - if (!split[i]) continue; // ignore empty strings - namespaces = split[i].replace(/\*/g, '.*?'); - if (namespaces[0] === '-') { - exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); - } else { - exports.names.push(new RegExp('^' + namespaces + '$')); - } - } -} - -/** - * Disable debug output. - * - * @api public - */ - -function disable() { - exports.enable(''); -} - -/** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ - -function enabled(name) { - var i, len; - for (i = 0, len = exports.skips.length; i < len; i++) { - if (exports.skips[i].test(name)) { - return false; - } - } - for (i = 0, len = exports.names.length; i < len; i++) { - if (exports.names[i].test(name)) { - return true; - } - } - return false; -} - -/** - * Coerce `val`. - * - * @param {Mixed} val - * @return {Mixed} - * @api private - */ - -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} - - -/***/ }), -/* 804 */ -/***/ (function(module, exports) { - -/** - * Helpers. - */ - -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; - -/** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @param {String|Number} val - * @param {Object} [options] - * @throws {Error} throw an error if val is not a non-empty string or a number - * @return {String|Number} - * @api public - */ - -module.exports = function(val, options) { - options = options || {}; - var type = typeof val; - if (type === 'string' && val.length > 0) { - return parse(val); - } else if (type === 'number' && isNaN(val) === false) { - return options.long ? fmtLong(val) : fmtShort(val); - } - throw new Error( - 'val is not a non-empty string or a valid number. val=' + - JSON.stringify(val) - ); -}; - -/** - * Parse the given `str` and return milliseconds. - * - * @param {String} str - * @return {Number} - * @api private - */ - -function parse(str) { - str = String(str); - if (str.length > 100) { - return; - } - var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( - str - ); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'yrs': - case 'yr': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'hrs': - case 'hr': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'mins': - case 'min': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 'secs': - case 'sec': - case 's': - return n * s; - case 'milliseconds': - case 'millisecond': - case 'msecs': - case 'msec': - case 'ms': - return n; - default: - return undefined; - } -} - -/** - * Short format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtShort(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; -} - -/** - * Long format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtLong(ms) { - return plural(ms, d, 'day') || - plural(ms, h, 'hour') || - plural(ms, m, 'minute') || - plural(ms, s, 'second') || - ms + ' ms'; -} - -/** - * Pluralization helper. - */ - -function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; - } - return Math.ceil(ms / n) + ' ' + name + 's'; -} - - -/***/ }), -/* 805 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * Module dependencies. - */ - -var tty = __webpack_require__(480); -var util = __webpack_require__(29); - -/** - * This is the Node.js implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = __webpack_require__(803); -exports.init = init; -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; - -/** - * Colors. - */ - -exports.colors = [6, 2, 3, 4, 5, 1]; - -/** - * Build up the default `inspectOpts` object from the environment variables. - * - * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js - */ - -exports.inspectOpts = Object.keys(process.env).filter(function (key) { - return /^debug_/i.test(key); -}).reduce(function (obj, key) { - // camel-case - var prop = key - .substring(6) - .toLowerCase() - .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); - - // coerce string value into JS value - var val = process.env[key]; - if (/^(yes|on|true|enabled)$/i.test(val)) val = true; - else if (/^(no|off|false|disabled)$/i.test(val)) val = false; - else if (val === 'null') val = null; - else val = Number(val); - - obj[prop] = val; - return obj; -}, {}); - -/** - * The file descriptor to write the `debug()` calls to. - * Set the `DEBUG_FD` env variable to override with another value. i.e.: - * - * $ DEBUG_FD=3 node script.js 3>debug.log - */ - -var fd = parseInt(process.env.DEBUG_FD, 10) || 2; - -if (1 !== fd && 2 !== fd) { - util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')() -} - -var stream = 1 === fd ? process.stdout : - 2 === fd ? process.stderr : - createWritableStdioStream(fd); - -/** - * Is stdout a TTY? Colored output is enabled when `true`. - */ - -function useColors() { - return 'colors' in exports.inspectOpts - ? Boolean(exports.inspectOpts.colors) - : tty.isatty(fd); -} - -/** - * Map %o to `util.inspect()`, all on a single line. - */ - -exports.formatters.o = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts) - .split('\n').map(function(str) { - return str.trim() - }).join(' '); -}; - -/** - * Map %o to `util.inspect()`, allowing multiple lines if needed. - */ - -exports.formatters.O = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts); -}; - -/** - * Adds ANSI color escape codes if enabled. - * - * @api public - */ - -function formatArgs(args) { - var name = this.namespace; - var useColors = this.useColors; - - if (useColors) { - var c = this.color; - var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; - - args[0] = prefix + args[0].split('\n').join('\n' + prefix); - args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); - } else { - args[0] = new Date().toUTCString() - + ' ' + name + ' ' + args[0]; - } -} - -/** - * Invokes `util.format()` with the specified arguments and writes to `stream`. - */ - -function log() { - return stream.write(util.format.apply(util, arguments) + '\n'); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - if (null == namespaces) { - // If you set a process.env field to null or undefined, it gets cast to the - // string 'null' or 'undefined'. Just delete instead. - delete process.env.DEBUG; - } else { - process.env.DEBUG = namespaces; - } -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - return process.env.DEBUG; -} - -/** - * Copied from `node/src/node.js`. - * - * XXX: It's lame that node doesn't expose this API out-of-the-box. It also - * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. - */ - -function createWritableStdioStream (fd) { - var stream; - var tty_wrap = process.binding('tty_wrap'); - - // Note stream._type is used for test-module-load-list.js - - switch (tty_wrap.guessHandleType(fd)) { - case 'TTY': - stream = new tty.WriteStream(fd); - stream._type = 'tty'; - - // Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - case 'FILE': - var fs = __webpack_require__(23); - stream = new fs.SyncWriteStream(fd, { autoClose: false }); - stream._type = 'fs'; - break; - - case 'PIPE': - case 'TCP': - var net = __webpack_require__(806); - stream = new net.Socket({ - fd: fd, - readable: false, - writable: true - }); - - // FIXME Should probably have an option in net.Socket to create a - // stream from an existing fd which is writable only. But for now - // we'll just add this hack and set the `readable` member to false. - // Test: ./node test/fixtures/echo.js < /etc/passwd - stream.readable = false; - stream.read = null; - stream._type = 'pipe'; - - // FIXME Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - default: - // Probably an error on in uv_guess_handle() - throw new Error('Implement me. Unknown stream file type!'); - } - - // For supporting legacy API we put the FD here. - stream.fd = fd; - - stream._isStdio = true; - - return stream; -} - -/** - * Init logic for `debug` instances. - * - * Create a new `inspectOpts` object in case `useColors` is set - * differently for a particular `debug` instance. - */ - -function init (debug) { - debug.inspectOpts = {}; - - var keys = Object.keys(exports.inspectOpts); - for (var i = 0; i < keys.length; i++) { - debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; - } -} - -/** - * Enable namespaces listed in `process.env.DEBUG` initially. - */ - -exports.enable(load()); - - -/***/ }), -/* 806 */ -/***/ (function(module, exports) { - -module.exports = require("net"); - -/***/ }), -/* 807 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Module dependencies - */ - -exports.extend = __webpack_require__(738); -exports.SourceMap = __webpack_require__(808); -exports.sourceMapResolve = __webpack_require__(819); - -/** - * Convert backslash in the given string to forward slashes - */ - -exports.unixify = function(fp) { - return fp.split(/\\+/).join('/'); -}; - -/** - * Return true if `val` is a non-empty string - * - * @param {String} `str` - * @return {Boolean} - */ - -exports.isString = function(str) { - return str && typeof str === 'string'; -}; - -/** - * Cast `val` to an array - * @return {Array} - */ - -exports.arrayify = function(val) { - if (typeof val === 'string') return [val]; - return val ? (Array.isArray(val) ? val : [val]) : []; -}; - -/** - * Get the last `n` element from the given `array` - * @param {Array} `array` - * @return {*} - */ - -exports.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; - - -/***/ }), -/* 808 */ -/***/ (function(module, exports, __webpack_require__) { - -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ -exports.SourceMapGenerator = __webpack_require__(809).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(815).SourceMapConsumer; -exports.SourceNode = __webpack_require__(818).SourceNode; - - -/***/ }), -/* 809 */ -/***/ (function(module, exports, __webpack_require__) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var base64VLQ = __webpack_require__(810); -var util = __webpack_require__(812); -var ArraySet = __webpack_require__(813).ArraySet; -var MappingList = __webpack_require__(814).MappingList; - -/** - * An instance of the SourceMapGenerator represents a source map which is - * being built incrementally. You may pass an object with the following - * properties: - * - * - file: The filename of the generated source. - * - sourceRoot: A root for all relative URLs in this source map. - */ -function SourceMapGenerator(aArgs) { - if (!aArgs) { - aArgs = {}; - } - this._file = util.getArg(aArgs, 'file', null); - this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); - this._skipValidation = util.getArg(aArgs, 'skipValidation', false); - this._sources = new ArraySet(); - this._names = new ArraySet(); - this._mappings = new MappingList(); - this._sourcesContents = null; -} - -SourceMapGenerator.prototype._version = 3; - -/** - * Creates a new SourceMapGenerator based on a SourceMapConsumer - * - * @param aSourceMapConsumer The SourceMap. - */ -SourceMapGenerator.fromSourceMap = - function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { - var sourceRoot = aSourceMapConsumer.sourceRoot; - var generator = new SourceMapGenerator({ - file: aSourceMapConsumer.file, - sourceRoot: sourceRoot - }); - aSourceMapConsumer.eachMapping(function (mapping) { - var newMapping = { - generated: { - line: mapping.generatedLine, - column: mapping.generatedColumn - } - }; - - if (mapping.source != null) { - newMapping.source = mapping.source; - if (sourceRoot != null) { - newMapping.source = util.relative(sourceRoot, newMapping.source); - } - - newMapping.original = { - line: mapping.originalLine, - column: mapping.originalColumn - }; - - if (mapping.name != null) { - newMapping.name = mapping.name; - } - } - - generator.addMapping(newMapping); - }); - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content != null) { - generator.setSourceContent(sourceFile, content); - } - }); - return generator; - }; - -/** - * Add a single mapping from original source line and column to the generated - * source's line and column for this source map being created. The mapping - * object should have the following properties: - * - * - generated: An object with the generated line and column positions. - * - original: An object with the original line and column positions. - * - source: The original source file (relative to the sourceRoot). - * - name: An optional original token name for this mapping. - */ -SourceMapGenerator.prototype.addMapping = - function SourceMapGenerator_addMapping(aArgs) { - var generated = util.getArg(aArgs, 'generated'); - var original = util.getArg(aArgs, 'original', null); - var source = util.getArg(aArgs, 'source', null); - var name = util.getArg(aArgs, 'name', null); - - if (!this._skipValidation) { - this._validateMapping(generated, original, source, name); - } - - if (source != null) { - source = String(source); - if (!this._sources.has(source)) { - this._sources.add(source); - } - } - - if (name != null) { - name = String(name); - if (!this._names.has(name)) { - this._names.add(name); - } - } - - this._mappings.add({ - generatedLine: generated.line, - generatedColumn: generated.column, - originalLine: original != null && original.line, - originalColumn: original != null && original.column, - source: source, - name: name - }); - }; - -/** - * Set the source content for a source file. - */ -SourceMapGenerator.prototype.setSourceContent = - function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { - var source = aSourceFile; - if (this._sourceRoot != null) { - source = util.relative(this._sourceRoot, source); - } - - if (aSourceContent != null) { - // Add the source content to the _sourcesContents map. - // Create a new _sourcesContents map if the property is null. - if (!this._sourcesContents) { - this._sourcesContents = Object.create(null); - } - this._sourcesContents[util.toSetString(source)] = aSourceContent; - } else if (this._sourcesContents) { - // Remove the source file from the _sourcesContents map. - // If the _sourcesContents map is empty, set the property to null. - delete this._sourcesContents[util.toSetString(source)]; - if (Object.keys(this._sourcesContents).length === 0) { - this._sourcesContents = null; - } - } - }; - -/** - * Applies the mappings of a sub-source-map for a specific source file to the - * source map being generated. Each mapping to the supplied source file is - * rewritten using the supplied source map. Note: The resolution for the - * resulting mappings is the minimium of this map and the supplied map. - * - * @param aSourceMapConsumer The source map to be applied. - * @param aSourceFile Optional. The filename of the source file. - * If omitted, SourceMapConsumer's file property will be used. - * @param aSourceMapPath Optional. The dirname of the path to the source map - * to be applied. If relative, it is relative to the SourceMapConsumer. - * This parameter is needed when the two source maps aren't in the same - * directory, and the source map to be applied contains relative source - * paths. If so, those relative source paths need to be rewritten - * relative to the SourceMapGenerator. - */ -SourceMapGenerator.prototype.applySourceMap = - function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) { - var sourceFile = aSourceFile; - // If aSourceFile is omitted, we will use the file property of the SourceMap - if (aSourceFile == null) { - if (aSourceMapConsumer.file == null) { - throw new Error( - 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' + - 'or the source map\'s "file" property. Both were omitted.' - ); - } - sourceFile = aSourceMapConsumer.file; - } - var sourceRoot = this._sourceRoot; - // Make "sourceFile" relative if an absolute Url is passed. - if (sourceRoot != null) { - sourceFile = util.relative(sourceRoot, sourceFile); - } - // Applying the SourceMap can add and remove items from the sources and - // the names array. - var newSources = new ArraySet(); - var newNames = new ArraySet(); - - // Find mappings for the "sourceFile" - this._mappings.unsortedForEach(function (mapping) { - if (mapping.source === sourceFile && mapping.originalLine != null) { - // Check if it can be mapped by the source map, then update the mapping. - var original = aSourceMapConsumer.originalPositionFor({ - line: mapping.originalLine, - column: mapping.originalColumn - }); - if (original.source != null) { - // Copy mapping - mapping.source = original.source; - if (aSourceMapPath != null) { - mapping.source = util.join(aSourceMapPath, mapping.source) - } - if (sourceRoot != null) { - mapping.source = util.relative(sourceRoot, mapping.source); - } - mapping.originalLine = original.line; - mapping.originalColumn = original.column; - if (original.name != null) { - mapping.name = original.name; - } - } - } - - var source = mapping.source; - if (source != null && !newSources.has(source)) { - newSources.add(source); - } - - var name = mapping.name; - if (name != null && !newNames.has(name)) { - newNames.add(name); - } - - }, this); - this._sources = newSources; - this._names = newNames; - - // Copy sourcesContents of applied map. - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content != null) { - if (aSourceMapPath != null) { - sourceFile = util.join(aSourceMapPath, sourceFile); - } - if (sourceRoot != null) { - sourceFile = util.relative(sourceRoot, sourceFile); - } - this.setSourceContent(sourceFile, content); - } - }, this); - }; - -/** - * A mapping can have one of the three levels of data: - * - * 1. Just the generated position. - * 2. The Generated position, original position, and original source. - * 3. Generated and original position, original source, as well as a name - * token. - * - * To maintain consistency, we validate that any new mapping being added falls - * in to one of these categories. - */ -SourceMapGenerator.prototype._validateMapping = - function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, - aName) { - // When aOriginal is truthy but has empty values for .line and .column, - // it is most likely a programmer error. In this case we throw a very - // specific error message to try to guide them the right way. - // For example: https://github.com/Polymer/polymer-bundler/pull/519 - if (aOriginal && typeof aOriginal.line !== 'number' && typeof aOriginal.column !== 'number') { - throw new Error( - 'original.line and original.column are not numbers -- you probably meant to omit ' + - 'the original mapping entirely and only map the generated position. If so, pass ' + - 'null for the original mapping instead of an object with empty or null values.' - ); - } - - if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aGenerated.line > 0 && aGenerated.column >= 0 - && !aOriginal && !aSource && !aName) { - // Case 1. - return; - } - else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aOriginal && 'line' in aOriginal && 'column' in aOriginal - && aGenerated.line > 0 && aGenerated.column >= 0 - && aOriginal.line > 0 && aOriginal.column >= 0 - && aSource) { - // Cases 2 and 3. - return; - } - else { - throw new Error('Invalid mapping: ' + JSON.stringify({ - generated: aGenerated, - source: aSource, - original: aOriginal, - name: aName - })); - } - }; - -/** - * Serialize the accumulated mappings in to the stream of base 64 VLQs - * specified by the source map format. - */ -SourceMapGenerator.prototype._serializeMappings = - function SourceMapGenerator_serializeMappings() { - var previousGeneratedColumn = 0; - var previousGeneratedLine = 1; - var previousOriginalColumn = 0; - var previousOriginalLine = 0; - var previousName = 0; - var previousSource = 0; - var result = ''; - var next; - var mapping; - var nameIdx; - var sourceIdx; - - var mappings = this._mappings.toArray(); - for (var i = 0, len = mappings.length; i < len; i++) { - mapping = mappings[i]; - next = '' - - if (mapping.generatedLine !== previousGeneratedLine) { - previousGeneratedColumn = 0; - while (mapping.generatedLine !== previousGeneratedLine) { - next += ';'; - previousGeneratedLine++; - } - } - else { - if (i > 0) { - if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) { - continue; - } - next += ','; - } - } - - next += base64VLQ.encode(mapping.generatedColumn - - previousGeneratedColumn); - previousGeneratedColumn = mapping.generatedColumn; - - if (mapping.source != null) { - sourceIdx = this._sources.indexOf(mapping.source); - next += base64VLQ.encode(sourceIdx - previousSource); - previousSource = sourceIdx; - - // lines are stored 0-based in SourceMap spec version 3 - next += base64VLQ.encode(mapping.originalLine - 1 - - previousOriginalLine); - previousOriginalLine = mapping.originalLine - 1; - - next += base64VLQ.encode(mapping.originalColumn - - previousOriginalColumn); - previousOriginalColumn = mapping.originalColumn; - - if (mapping.name != null) { - nameIdx = this._names.indexOf(mapping.name); - next += base64VLQ.encode(nameIdx - previousName); - previousName = nameIdx; - } - } - - result += next; - } - - return result; - }; - -SourceMapGenerator.prototype._generateSourcesContent = - function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { - return aSources.map(function (source) { - if (!this._sourcesContents) { - return null; - } - if (aSourceRoot != null) { - source = util.relative(aSourceRoot, source); - } - var key = util.toSetString(source); - return Object.prototype.hasOwnProperty.call(this._sourcesContents, key) - ? this._sourcesContents[key] - : null; - }, this); - }; - -/** - * Externalize the source map. - */ -SourceMapGenerator.prototype.toJSON = - function SourceMapGenerator_toJSON() { - var map = { - version: this._version, - sources: this._sources.toArray(), - names: this._names.toArray(), - mappings: this._serializeMappings() - }; - if (this._file != null) { - map.file = this._file; - } - if (this._sourceRoot != null) { - map.sourceRoot = this._sourceRoot; - } - if (this._sourcesContents) { - map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); - } - - return map; - }; - -/** - * Render the source map being generated to a string. - */ -SourceMapGenerator.prototype.toString = - function SourceMapGenerator_toString() { - return JSON.stringify(this.toJSON()); - }; - -exports.SourceMapGenerator = SourceMapGenerator; - - -/***/ }), -/* 810 */ -/***/ (function(module, exports, __webpack_require__) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - * - * Based on the Base 64 VLQ implementation in Closure Compiler: - * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java - * - * Copyright 2011 The Closure Compiler Authors. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -var base64 = __webpack_require__(811); - -// A single base 64 digit can contain 6 bits of data. For the base 64 variable -// length quantities we use in the source map spec, the first bit is the sign, -// the next four bits are the actual value, and the 6th bit is the -// continuation bit. The continuation bit tells us whether there are more -// digits in this value following this digit. -// -// Continuation -// | Sign -// | | -// V V -// 101011 - -var VLQ_BASE_SHIFT = 5; - -// binary: 100000 -var VLQ_BASE = 1 << VLQ_BASE_SHIFT; - -// binary: 011111 -var VLQ_BASE_MASK = VLQ_BASE - 1; - -// binary: 100000 -var VLQ_CONTINUATION_BIT = VLQ_BASE; - -/** - * Converts from a two-complement value to a value where the sign bit is - * placed in the least significant bit. For example, as decimals: - * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) - * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) - */ -function toVLQSigned(aValue) { - return aValue < 0 - ? ((-aValue) << 1) + 1 - : (aValue << 1) + 0; -} - -/** - * Converts to a two-complement value from a value where the sign bit is - * placed in the least significant bit. For example, as decimals: - * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 - * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 - */ -function fromVLQSigned(aValue) { - var isNegative = (aValue & 1) === 1; - var shifted = aValue >> 1; - return isNegative - ? -shifted - : shifted; -} - -/** - * Returns the base 64 VLQ encoded value. - */ -exports.encode = function base64VLQ_encode(aValue) { - var encoded = ""; - var digit; - - var vlq = toVLQSigned(aValue); - - do { - digit = vlq & VLQ_BASE_MASK; - vlq >>>= VLQ_BASE_SHIFT; - if (vlq > 0) { - // There are still more digits in this value, so we must make sure the - // continuation bit is marked. - digit |= VLQ_CONTINUATION_BIT; - } - encoded += base64.encode(digit); - } while (vlq > 0); - - return encoded; -}; - -/** - * Decodes the next base 64 VLQ value from the given string and returns the - * value and the rest of the string via the out parameter. - */ -exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { - var strLen = aStr.length; - var result = 0; - var shift = 0; - var continuation, digit; - - do { - if (aIndex >= strLen) { - throw new Error("Expected more digits in base 64 VLQ value."); - } - - digit = base64.decode(aStr.charCodeAt(aIndex++)); - if (digit === -1) { - throw new Error("Invalid base64 digit: " + aStr.charAt(aIndex - 1)); - } - - continuation = !!(digit & VLQ_CONTINUATION_BIT); - digit &= VLQ_BASE_MASK; - result = result + (digit << shift); - shift += VLQ_BASE_SHIFT; - } while (continuation); - - aOutParam.value = fromVLQSigned(result); - aOutParam.rest = aIndex; -}; - - -/***/ }), -/* 811 */ -/***/ (function(module, exports) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var intToCharMap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); - -/** - * Encode an integer in the range of 0 to 63 to a single base 64 digit. - */ -exports.encode = function (number) { - if (0 <= number && number < intToCharMap.length) { - return intToCharMap[number]; - } - throw new TypeError("Must be between 0 and 63: " + number); -}; - -/** - * Decode a single base 64 character code digit to an integer. Returns -1 on - * failure. - */ -exports.decode = function (charCode) { - var bigA = 65; // 'A' - var bigZ = 90; // 'Z' - - var littleA = 97; // 'a' - var littleZ = 122; // 'z' - - var zero = 48; // '0' - var nine = 57; // '9' - - var plus = 43; // '+' - var slash = 47; // '/' - - var littleOffset = 26; - var numberOffset = 52; - - // 0 - 25: ABCDEFGHIJKLMNOPQRSTUVWXYZ - if (bigA <= charCode && charCode <= bigZ) { - return (charCode - bigA); - } - - // 26 - 51: abcdefghijklmnopqrstuvwxyz - if (littleA <= charCode && charCode <= littleZ) { - return (charCode - littleA + littleOffset); - } - - // 52 - 61: 0123456789 - if (zero <= charCode && charCode <= nine) { - return (charCode - zero + numberOffset); - } - - // 62: + - if (charCode == plus) { - return 62; - } - - // 63: / - if (charCode == slash) { - return 63; - } - - // Invalid base64 digit. - return -1; -}; - - -/***/ }), -/* 812 */ -/***/ (function(module, exports) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -/** - * This is a helper function for getting values from parameter/options - * objects. - * - * @param args The object we are extracting values from - * @param name The name of the property we are getting. - * @param defaultValue An optional value to return if the property is missing - * from the object. If this is not specified and the property is missing, an - * error will be thrown. - */ -function getArg(aArgs, aName, aDefaultValue) { - if (aName in aArgs) { - return aArgs[aName]; - } else if (arguments.length === 3) { - return aDefaultValue; - } else { - throw new Error('"' + aName + '" is a required argument.'); - } -} -exports.getArg = getArg; - -var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/; -var dataUrlRegexp = /^data:.+\,.+$/; - -function urlParse(aUrl) { - var match = aUrl.match(urlRegexp); - if (!match) { - return null; - } - return { - scheme: match[1], - auth: match[2], - host: match[3], - port: match[4], - path: match[5] - }; -} -exports.urlParse = urlParse; - -function urlGenerate(aParsedUrl) { - var url = ''; - if (aParsedUrl.scheme) { - url += aParsedUrl.scheme + ':'; - } - url += '//'; - if (aParsedUrl.auth) { - url += aParsedUrl.auth + '@'; - } - if (aParsedUrl.host) { - url += aParsedUrl.host; - } - if (aParsedUrl.port) { - url += ":" + aParsedUrl.port - } - if (aParsedUrl.path) { - url += aParsedUrl.path; - } - return url; -} -exports.urlGenerate = urlGenerate; - -/** - * Normalizes a path, or the path portion of a URL: - * - * - Replaces consecutive slashes with one slash. - * - Removes unnecessary '.' parts. - * - Removes unnecessary '/..' parts. - * - * Based on code in the Node.js 'path' core module. - * - * @param aPath The path or url to normalize. - */ -function normalize(aPath) { - var path = aPath; - var url = urlParse(aPath); - if (url) { - if (!url.path) { - return aPath; - } - path = url.path; - } - var isAbsolute = exports.isAbsolute(path); - - var parts = path.split(/\/+/); - for (var part, up = 0, i = parts.length - 1; i >= 0; i--) { - part = parts[i]; - if (part === '.') { - parts.splice(i, 1); - } else if (part === '..') { - up++; - } else if (up > 0) { - if (part === '') { - // The first part is blank if the path is absolute. Trying to go - // above the root is a no-op. Therefore we can remove all '..' parts - // directly after the root. - parts.splice(i + 1, up); - up = 0; - } else { - parts.splice(i, 2); - up--; - } - } - } - path = parts.join('/'); - - if (path === '') { - path = isAbsolute ? '/' : '.'; - } - - if (url) { - url.path = path; - return urlGenerate(url); - } - return path; -} -exports.normalize = normalize; - -/** - * Joins two paths/URLs. - * - * @param aRoot The root path or URL. - * @param aPath The path or URL to be joined with the root. - * - * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a - * scheme-relative URL: Then the scheme of aRoot, if any, is prepended - * first. - * - Otherwise aPath is a path. If aRoot is a URL, then its path portion - * is updated with the result and aRoot is returned. Otherwise the result - * is returned. - * - If aPath is absolute, the result is aPath. - * - Otherwise the two paths are joined with a slash. - * - Joining for example 'http://' and 'www.example.com' is also supported. - */ -function join(aRoot, aPath) { - if (aRoot === "") { - aRoot = "."; - } - if (aPath === "") { - aPath = "."; - } - var aPathUrl = urlParse(aPath); - var aRootUrl = urlParse(aRoot); - if (aRootUrl) { - aRoot = aRootUrl.path || '/'; - } - - // `join(foo, '//www.example.org')` - if (aPathUrl && !aPathUrl.scheme) { - if (aRootUrl) { - aPathUrl.scheme = aRootUrl.scheme; - } - return urlGenerate(aPathUrl); - } - - if (aPathUrl || aPath.match(dataUrlRegexp)) { - return aPath; - } - - // `join('http://', 'www.example.com')` - if (aRootUrl && !aRootUrl.host && !aRootUrl.path) { - aRootUrl.host = aPath; - return urlGenerate(aRootUrl); - } - - var joined = aPath.charAt(0) === '/' - ? aPath - : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath); - - if (aRootUrl) { - aRootUrl.path = joined; - return urlGenerate(aRootUrl); - } - return joined; -} -exports.join = join; - -exports.isAbsolute = function (aPath) { - return aPath.charAt(0) === '/' || !!aPath.match(urlRegexp); -}; - -/** - * Make a path relative to a URL or another path. - * - * @param aRoot The root path or URL. - * @param aPath The path or URL to be made relative to aRoot. - */ -function relative(aRoot, aPath) { - if (aRoot === "") { - aRoot = "."; - } - - aRoot = aRoot.replace(/\/$/, ''); - - // It is possible for the path to be above the root. In this case, simply - // checking whether the root is a prefix of the path won't work. Instead, we - // need to remove components from the root one by one, until either we find - // a prefix that fits, or we run out of components to remove. - var level = 0; - while (aPath.indexOf(aRoot + '/') !== 0) { - var index = aRoot.lastIndexOf("/"); - if (index < 0) { - return aPath; - } - - // If the only part of the root that is left is the scheme (i.e. http://, - // file:///, etc.), one or more slashes (/), or simply nothing at all, we - // have exhausted all components, so the path is not relative to the root. - aRoot = aRoot.slice(0, index); - if (aRoot.match(/^([^\/]+:\/)?\/*$/)) { - return aPath; - } - - ++level; - } - - // Make sure we add a "../" for each component we removed from the root. - return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1); -} -exports.relative = relative; - -var supportsNullProto = (function () { - var obj = Object.create(null); - return !('__proto__' in obj); -}()); - -function identity (s) { - return s; -} - -/** - * Because behavior goes wacky when you set `__proto__` on objects, we - * have to prefix all the strings in our set with an arbitrary character. - * - * See https://github.com/mozilla/source-map/pull/31 and - * https://github.com/mozilla/source-map/issues/30 - * - * @param String aStr - */ -function toSetString(aStr) { - if (isProtoString(aStr)) { - return '$' + aStr; - } - - return aStr; -} -exports.toSetString = supportsNullProto ? identity : toSetString; - -function fromSetString(aStr) { - if (isProtoString(aStr)) { - return aStr.slice(1); - } - - return aStr; -} -exports.fromSetString = supportsNullProto ? identity : fromSetString; - -function isProtoString(s) { - if (!s) { - return false; - } - - var length = s.length; - - if (length < 9 /* "__proto__".length */) { - return false; - } - - if (s.charCodeAt(length - 1) !== 95 /* '_' */ || - s.charCodeAt(length - 2) !== 95 /* '_' */ || - s.charCodeAt(length - 3) !== 111 /* 'o' */ || - s.charCodeAt(length - 4) !== 116 /* 't' */ || - s.charCodeAt(length - 5) !== 111 /* 'o' */ || - s.charCodeAt(length - 6) !== 114 /* 'r' */ || - s.charCodeAt(length - 7) !== 112 /* 'p' */ || - s.charCodeAt(length - 8) !== 95 /* '_' */ || - s.charCodeAt(length - 9) !== 95 /* '_' */) { - return false; - } - - for (var i = length - 10; i >= 0; i--) { - if (s.charCodeAt(i) !== 36 /* '$' */) { - return false; - } - } - - return true; -} - -/** - * Comparator between two mappings where the original positions are compared. - * - * Optionally pass in `true` as `onlyCompareGenerated` to consider two - * mappings with the same original source/line/column, but different generated - * line and column the same. Useful when searching for a mapping with a - * stubbed out mapping. - */ -function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { - var cmp = mappingA.source - mappingB.source; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.originalLine - mappingB.originalLine; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.originalColumn - mappingB.originalColumn; - if (cmp !== 0 || onlyCompareOriginal) { - return cmp; - } - - cmp = mappingA.generatedColumn - mappingB.generatedColumn; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.generatedLine - mappingB.generatedLine; - if (cmp !== 0) { - return cmp; - } - - return mappingA.name - mappingB.name; -} -exports.compareByOriginalPositions = compareByOriginalPositions; - -/** - * Comparator between two mappings with deflated source and name indices where - * the generated positions are compared. - * - * Optionally pass in `true` as `onlyCompareGenerated` to consider two - * mappings with the same generated line and column, but different - * source/name/original line and column the same. Useful when searching for a - * mapping with a stubbed out mapping. - */ -function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) { - var cmp = mappingA.generatedLine - mappingB.generatedLine; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.generatedColumn - mappingB.generatedColumn; - if (cmp !== 0 || onlyCompareGenerated) { - return cmp; - } - - cmp = mappingA.source - mappingB.source; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.originalLine - mappingB.originalLine; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.originalColumn - mappingB.originalColumn; - if (cmp !== 0) { - return cmp; - } - - return mappingA.name - mappingB.name; -} -exports.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated; - -function strcmp(aStr1, aStr2) { - if (aStr1 === aStr2) { - return 0; - } - - if (aStr1 > aStr2) { - return 1; - } - - return -1; -} - -/** - * Comparator between two mappings with inflated source and name strings where - * the generated positions are compared. - */ -function compareByGeneratedPositionsInflated(mappingA, mappingB) { - var cmp = mappingA.generatedLine - mappingB.generatedLine; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.generatedColumn - mappingB.generatedColumn; - if (cmp !== 0) { - return cmp; - } - - cmp = strcmp(mappingA.source, mappingB.source); - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.originalLine - mappingB.originalLine; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.originalColumn - mappingB.originalColumn; - if (cmp !== 0) { - return cmp; - } - - return strcmp(mappingA.name, mappingB.name); -} -exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated; - - -/***/ }), -/* 813 */ -/***/ (function(module, exports, __webpack_require__) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var util = __webpack_require__(812); -var has = Object.prototype.hasOwnProperty; -var hasNativeMap = typeof Map !== "undefined"; - -/** - * A data structure which is a combination of an array and a set. Adding a new - * member is O(1), testing for membership is O(1), and finding the index of an - * element is O(1). Removing elements from the set is not supported. Only - * strings are supported for membership. - */ -function ArraySet() { - this._array = []; - this._set = hasNativeMap ? new Map() : Object.create(null); -} - -/** - * Static method for creating ArraySet instances from an existing array. - */ -ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { - var set = new ArraySet(); - for (var i = 0, len = aArray.length; i < len; i++) { - set.add(aArray[i], aAllowDuplicates); - } - return set; -}; - -/** - * Return how many unique items are in this ArraySet. If duplicates have been - * added, than those do not count towards the size. - * - * @returns Number - */ -ArraySet.prototype.size = function ArraySet_size() { - return hasNativeMap ? this._set.size : Object.getOwnPropertyNames(this._set).length; -}; - -/** - * Add the given string to this set. - * - * @param String aStr - */ -ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { - var sStr = hasNativeMap ? aStr : util.toSetString(aStr); - var isDuplicate = hasNativeMap ? this.has(aStr) : has.call(this._set, sStr); - var idx = this._array.length; - if (!isDuplicate || aAllowDuplicates) { - this._array.push(aStr); - } - if (!isDuplicate) { - if (hasNativeMap) { - this._set.set(aStr, idx); - } else { - this._set[sStr] = idx; - } - } -}; - -/** - * Is the given string a member of this set? - * - * @param String aStr - */ -ArraySet.prototype.has = function ArraySet_has(aStr) { - if (hasNativeMap) { - return this._set.has(aStr); - } else { - var sStr = util.toSetString(aStr); - return has.call(this._set, sStr); - } -}; - -/** - * What is the index of the given string in the array? - * - * @param String aStr - */ -ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { - if (hasNativeMap) { - var idx = this._set.get(aStr); - if (idx >= 0) { - return idx; - } - } else { - var sStr = util.toSetString(aStr); - if (has.call(this._set, sStr)) { - return this._set[sStr]; - } - } - - throw new Error('"' + aStr + '" is not in the set.'); -}; - -/** - * What is the element at the given index? - * - * @param Number aIdx - */ -ArraySet.prototype.at = function ArraySet_at(aIdx) { - if (aIdx >= 0 && aIdx < this._array.length) { - return this._array[aIdx]; - } - throw new Error('No element indexed by ' + aIdx); -}; - -/** - * Returns the array representation of this set (which has the proper indices - * indicated by indexOf). Note that this is a copy of the internal array used - * for storing the members so that no one can mess with internal state. - */ -ArraySet.prototype.toArray = function ArraySet_toArray() { - return this._array.slice(); -}; - -exports.ArraySet = ArraySet; - - -/***/ }), -/* 814 */ -/***/ (function(module, exports, __webpack_require__) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2014 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var util = __webpack_require__(812); - -/** - * Determine whether mappingB is after mappingA with respect to generated - * position. - */ -function generatedPositionAfter(mappingA, mappingB) { - // Optimized for most common case - var lineA = mappingA.generatedLine; - var lineB = mappingB.generatedLine; - var columnA = mappingA.generatedColumn; - var columnB = mappingB.generatedColumn; - return lineB > lineA || lineB == lineA && columnB >= columnA || - util.compareByGeneratedPositionsInflated(mappingA, mappingB) <= 0; -} - -/** - * A data structure to provide a sorted view of accumulated mappings in a - * performance conscious manner. It trades a neglibable overhead in general - * case for a large speedup in case of mappings being added in order. - */ -function MappingList() { - this._array = []; - this._sorted = true; - // Serves as infimum - this._last = {generatedLine: -1, generatedColumn: 0}; -} - -/** - * Iterate through internal items. This method takes the same arguments that - * `Array.prototype.forEach` takes. - * - * NOTE: The order of the mappings is NOT guaranteed. - */ -MappingList.prototype.unsortedForEach = - function MappingList_forEach(aCallback, aThisArg) { - this._array.forEach(aCallback, aThisArg); - }; - -/** - * Add the given source mapping. - * - * @param Object aMapping - */ -MappingList.prototype.add = function MappingList_add(aMapping) { - if (generatedPositionAfter(this._last, aMapping)) { - this._last = aMapping; - this._array.push(aMapping); - } else { - this._sorted = false; - this._array.push(aMapping); - } -}; - -/** - * Returns the flat, sorted array of mappings. The mappings are sorted by - * generated position. - * - * WARNING: This method returns internal data without copying, for - * performance. The return value must NOT be mutated, and should be treated as - * an immutable borrow. If you want to take ownership, you must make your own - * copy. - */ -MappingList.prototype.toArray = function MappingList_toArray() { - if (!this._sorted) { - this._array.sort(util.compareByGeneratedPositionsInflated); - this._sorted = true; - } - return this._array; -}; - -exports.MappingList = MappingList; - - -/***/ }), -/* 815 */ -/***/ (function(module, exports, __webpack_require__) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var util = __webpack_require__(812); -var binarySearch = __webpack_require__(816); -var ArraySet = __webpack_require__(813).ArraySet; -var base64VLQ = __webpack_require__(810); -var quickSort = __webpack_require__(817).quickSort; - -function SourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } - - return sourceMap.sections != null - ? new IndexedSourceMapConsumer(sourceMap) - : new BasicSourceMapConsumer(sourceMap); -} - -SourceMapConsumer.fromSourceMap = function(aSourceMap) { - return BasicSourceMapConsumer.fromSourceMap(aSourceMap); -} - -/** - * The version of the source mapping spec that we are consuming. - */ -SourceMapConsumer.prototype._version = 3; - -// `__generatedMappings` and `__originalMappings` are arrays that hold the -// parsed mapping coordinates from the source map's "mappings" attribute. They -// are lazily instantiated, accessed via the `_generatedMappings` and -// `_originalMappings` getters respectively, and we only parse the mappings -// and create these arrays once queried for a source location. We jump through -// these hoops because there can be many thousands of mappings, and parsing -// them is expensive, so we only want to do it if we must. -// -// Each object in the arrays is of the form: -// -// { -// generatedLine: The line number in the generated code, -// generatedColumn: The column number in the generated code, -// source: The path to the original source file that generated this -// chunk of code, -// originalLine: The line number in the original source that -// corresponds to this chunk of generated code, -// originalColumn: The column number in the original source that -// corresponds to this chunk of generated code, -// name: The name of the original symbol which generated this chunk of -// code. -// } -// -// All properties except for `generatedLine` and `generatedColumn` can be -// `null`. -// -// `_generatedMappings` is ordered by the generated positions. -// -// `_originalMappings` is ordered by the original positions. - -SourceMapConsumer.prototype.__generatedMappings = null; -Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', { - get: function () { - if (!this.__generatedMappings) { - this._parseMappings(this._mappings, this.sourceRoot); - } - - return this.__generatedMappings; - } -}); - -SourceMapConsumer.prototype.__originalMappings = null; -Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', { - get: function () { - if (!this.__originalMappings) { - this._parseMappings(this._mappings, this.sourceRoot); - } - - return this.__originalMappings; - } -}); - -SourceMapConsumer.prototype._charIsMappingSeparator = - function SourceMapConsumer_charIsMappingSeparator(aStr, index) { - var c = aStr.charAt(index); - return c === ";" || c === ","; - }; - -/** - * Parse the mappings in a string in to a data structure which we can easily - * query (the ordered arrays in the `this.__generatedMappings` and - * `this.__originalMappings` properties). - */ -SourceMapConsumer.prototype._parseMappings = - function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - throw new Error("Subclasses must implement _parseMappings"); - }; - -SourceMapConsumer.GENERATED_ORDER = 1; -SourceMapConsumer.ORIGINAL_ORDER = 2; - -SourceMapConsumer.GREATEST_LOWER_BOUND = 1; -SourceMapConsumer.LEAST_UPPER_BOUND = 2; - -/** - * Iterate over each mapping between an original source/line/column and a - * generated line/column in this source map. - * - * @param Function aCallback - * The function that is called with each mapping. - * @param Object aContext - * Optional. If specified, this object will be the value of `this` every - * time that `aCallback` is called. - * @param aOrder - * Either `SourceMapConsumer.GENERATED_ORDER` or - * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to - * iterate over the mappings sorted by the generated file's line/column - * order or the original's source/line/column order, respectively. Defaults to - * `SourceMapConsumer.GENERATED_ORDER`. - */ -SourceMapConsumer.prototype.eachMapping = - function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { - var context = aContext || null; - var order = aOrder || SourceMapConsumer.GENERATED_ORDER; - - var mappings; - switch (order) { - case SourceMapConsumer.GENERATED_ORDER: - mappings = this._generatedMappings; - break; - case SourceMapConsumer.ORIGINAL_ORDER: - mappings = this._originalMappings; - break; - default: - throw new Error("Unknown order of iteration."); - } - - var sourceRoot = this.sourceRoot; - mappings.map(function (mapping) { - var source = mapping.source === null ? null : this._sources.at(mapping.source); - if (source != null && sourceRoot != null) { - source = util.join(sourceRoot, source); - } - return { - source: source, - generatedLine: mapping.generatedLine, - generatedColumn: mapping.generatedColumn, - originalLine: mapping.originalLine, - originalColumn: mapping.originalColumn, - name: mapping.name === null ? null : this._names.at(mapping.name) - }; - }, this).forEach(aCallback, context); - }; - -/** - * Returns all generated line and column information for the original source, - * line, and column provided. If no column is provided, returns all mappings - * corresponding to a either the line we are searching for or the next - * closest line that has any mappings. Otherwise, returns all mappings - * corresponding to the given line and either the column we are searching for - * or the next closest column that has any offsets. - * - * The only argument is an object with the following properties: - * - * - source: The filename of the original source. - * - line: The line number in the original source. - * - column: Optional. the column number in the original source. - * - * and an array of objects is returned, each with the following properties: - * - * - line: The line number in the generated source, or null. - * - column: The column number in the generated source, or null. - */ -SourceMapConsumer.prototype.allGeneratedPositionsFor = - function SourceMapConsumer_allGeneratedPositionsFor(aArgs) { - var line = util.getArg(aArgs, 'line'); - - // When there is no exact match, BasicSourceMapConsumer.prototype._findMapping - // returns the index of the closest mapping less than the needle. By - // setting needle.originalColumn to 0, we thus find the last mapping for - // the given line, provided such a mapping exists. - var needle = { - source: util.getArg(aArgs, 'source'), - originalLine: line, - originalColumn: util.getArg(aArgs, 'column', 0) - }; - - if (this.sourceRoot != null) { - needle.source = util.relative(this.sourceRoot, needle.source); - } - if (!this._sources.has(needle.source)) { - return []; - } - needle.source = this._sources.indexOf(needle.source); - - var mappings = []; - - var index = this._findMapping(needle, - this._originalMappings, - "originalLine", - "originalColumn", - util.compareByOriginalPositions, - binarySearch.LEAST_UPPER_BOUND); - if (index >= 0) { - var mapping = this._originalMappings[index]; - - if (aArgs.column === undefined) { - var originalLine = mapping.originalLine; - - // Iterate until either we run out of mappings, or we run into - // a mapping for a different line than the one we found. Since - // mappings are sorted, this is guaranteed to find all mappings for - // the line we found. - while (mapping && mapping.originalLine === originalLine) { - mappings.push({ - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null), - lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) - }); - - mapping = this._originalMappings[++index]; - } - } else { - var originalColumn = mapping.originalColumn; - - // Iterate until either we run out of mappings, or we run into - // a mapping for a different line than the one we were searching for. - // Since mappings are sorted, this is guaranteed to find all mappings for - // the line we are searching for. - while (mapping && - mapping.originalLine === line && - mapping.originalColumn == originalColumn) { - mappings.push({ - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null), - lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) - }); - - mapping = this._originalMappings[++index]; - } - } - } - - return mappings; - }; - -exports.SourceMapConsumer = SourceMapConsumer; - -/** - * A BasicSourceMapConsumer instance represents a parsed source map which we can - * query for information about the original file positions by giving it a file - * position in the generated source. - * - * The only parameter is the raw source map (either as a JSON string, or - * already parsed to an object). According to the spec, source maps have the - * following attributes: - * - * - version: Which version of the source map spec this map is following. - * - sources: An array of URLs to the original source files. - * - names: An array of identifiers which can be referrenced by individual mappings. - * - sourceRoot: Optional. The URL root from which all sources are relative. - * - sourcesContent: Optional. An array of contents of the original source files. - * - mappings: A string of base64 VLQs which contain the actual mappings. - * - file: Optional. The generated file this source map is associated with. - * - * Here is an example source map, taken from the source map spec[0]: - * - * { - * version : 3, - * file: "out.js", - * sourceRoot : "", - * sources: ["foo.js", "bar.js"], - * names: ["src", "maps", "are", "fun"], - * mappings: "AA,AB;;ABCDE;" - * } - * - * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# - */ -function BasicSourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } - - var version = util.getArg(sourceMap, 'version'); - var sources = util.getArg(sourceMap, 'sources'); - // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which - // requires the array) to play nice here. - var names = util.getArg(sourceMap, 'names', []); - var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); - var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); - var mappings = util.getArg(sourceMap, 'mappings'); - var file = util.getArg(sourceMap, 'file', null); - - // Once again, Sass deviates from the spec and supplies the version as a - // string rather than a number, so we use loose equality checking here. - if (version != this._version) { - throw new Error('Unsupported version: ' + version); - } - - sources = sources - .map(String) - // Some source maps produce relative source paths like "./foo.js" instead of - // "foo.js". Normalize these first so that future comparisons will succeed. - // See bugzil.la/1090768. - .map(util.normalize) - // Always ensure that absolute sources are internally stored relative to - // the source root, if the source root is absolute. Not doing this would - // be particularly problematic when the source root is a prefix of the - // source (valid, but why??). See github issue #199 and bugzil.la/1188982. - .map(function (source) { - return sourceRoot && util.isAbsolute(sourceRoot) && util.isAbsolute(source) - ? util.relative(sourceRoot, source) - : source; - }); - - // Pass `true` below to allow duplicate names and sources. While source maps - // are intended to be compressed and deduplicated, the TypeScript compiler - // sometimes generates source maps with duplicates in them. See Github issue - // #72 and bugzil.la/889492. - this._names = ArraySet.fromArray(names.map(String), true); - this._sources = ArraySet.fromArray(sources, true); - - this.sourceRoot = sourceRoot; - this.sourcesContent = sourcesContent; - this._mappings = mappings; - this.file = file; -} - -BasicSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype); -BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer; - -/** - * Create a BasicSourceMapConsumer from a SourceMapGenerator. - * - * @param SourceMapGenerator aSourceMap - * The source map that will be consumed. - * @returns BasicSourceMapConsumer - */ -BasicSourceMapConsumer.fromSourceMap = - function SourceMapConsumer_fromSourceMap(aSourceMap) { - var smc = Object.create(BasicSourceMapConsumer.prototype); - - var names = smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true); - var sources = smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true); - smc.sourceRoot = aSourceMap._sourceRoot; - smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(), - smc.sourceRoot); - smc.file = aSourceMap._file; - - // Because we are modifying the entries (by converting string sources and - // names to indices into the sources and names ArraySets), we have to make - // a copy of the entry or else bad things happen. Shared mutable state - // strikes again! See github issue #191. - - var generatedMappings = aSourceMap._mappings.toArray().slice(); - var destGeneratedMappings = smc.__generatedMappings = []; - var destOriginalMappings = smc.__originalMappings = []; - - for (var i = 0, length = generatedMappings.length; i < length; i++) { - var srcMapping = generatedMappings[i]; - var destMapping = new Mapping; - destMapping.generatedLine = srcMapping.generatedLine; - destMapping.generatedColumn = srcMapping.generatedColumn; - - if (srcMapping.source) { - destMapping.source = sources.indexOf(srcMapping.source); - destMapping.originalLine = srcMapping.originalLine; - destMapping.originalColumn = srcMapping.originalColumn; - - if (srcMapping.name) { - destMapping.name = names.indexOf(srcMapping.name); - } - - destOriginalMappings.push(destMapping); - } - - destGeneratedMappings.push(destMapping); - } - - quickSort(smc.__originalMappings, util.compareByOriginalPositions); - - return smc; - }; - -/** - * The version of the source mapping spec that we are consuming. - */ -BasicSourceMapConsumer.prototype._version = 3; - -/** - * The list of original sources. - */ -Object.defineProperty(BasicSourceMapConsumer.prototype, 'sources', { - get: function () { - return this._sources.toArray().map(function (s) { - return this.sourceRoot != null ? util.join(this.sourceRoot, s) : s; - }, this); - } -}); - -/** - * Provide the JIT with a nice shape / hidden class. - */ -function Mapping() { - this.generatedLine = 0; - this.generatedColumn = 0; - this.source = null; - this.originalLine = null; - this.originalColumn = null; - this.name = null; -} - -/** - * Parse the mappings in a string in to a data structure which we can easily - * query (the ordered arrays in the `this.__generatedMappings` and - * `this.__originalMappings` properties). - */ -BasicSourceMapConsumer.prototype._parseMappings = - function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - var generatedLine = 1; - var previousGeneratedColumn = 0; - var previousOriginalLine = 0; - var previousOriginalColumn = 0; - var previousSource = 0; - var previousName = 0; - var length = aStr.length; - var index = 0; - var cachedSegments = {}; - var temp = {}; - var originalMappings = []; - var generatedMappings = []; - var mapping, str, segment, end, value; - - while (index < length) { - if (aStr.charAt(index) === ';') { - generatedLine++; - index++; - previousGeneratedColumn = 0; - } - else if (aStr.charAt(index) === ',') { - index++; - } - else { - mapping = new Mapping(); - mapping.generatedLine = generatedLine; - - // Because each offset is encoded relative to the previous one, - // many segments often have the same encoding. We can exploit this - // fact by caching the parsed variable length fields of each segment, - // allowing us to avoid a second parse if we encounter the same - // segment again. - for (end = index; end < length; end++) { - if (this._charIsMappingSeparator(aStr, end)) { - break; - } - } - str = aStr.slice(index, end); - - segment = cachedSegments[str]; - if (segment) { - index += str.length; - } else { - segment = []; - while (index < end) { - base64VLQ.decode(aStr, index, temp); - value = temp.value; - index = temp.rest; - segment.push(value); - } - - if (segment.length === 2) { - throw new Error('Found a source, but no line and column'); - } - - if (segment.length === 3) { - throw new Error('Found a source and line, but no column'); - } - - cachedSegments[str] = segment; - } - - // Generated column. - mapping.generatedColumn = previousGeneratedColumn + segment[0]; - previousGeneratedColumn = mapping.generatedColumn; - - if (segment.length > 1) { - // Original source. - mapping.source = previousSource + segment[1]; - previousSource += segment[1]; - - // Original line. - mapping.originalLine = previousOriginalLine + segment[2]; - previousOriginalLine = mapping.originalLine; - // Lines are stored 0-based - mapping.originalLine += 1; - - // Original column. - mapping.originalColumn = previousOriginalColumn + segment[3]; - previousOriginalColumn = mapping.originalColumn; - - if (segment.length > 4) { - // Original name. - mapping.name = previousName + segment[4]; - previousName += segment[4]; - } - } - - generatedMappings.push(mapping); - if (typeof mapping.originalLine === 'number') { - originalMappings.push(mapping); - } - } - } - - quickSort(generatedMappings, util.compareByGeneratedPositionsDeflated); - this.__generatedMappings = generatedMappings; - - quickSort(originalMappings, util.compareByOriginalPositions); - this.__originalMappings = originalMappings; - }; - -/** - * Find the mapping that best matches the hypothetical "needle" mapping that - * we are searching for in the given "haystack" of mappings. - */ -BasicSourceMapConsumer.prototype._findMapping = - function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, - aColumnName, aComparator, aBias) { - // To return the position we are searching for, we must first find the - // mapping for the given position and then return the opposite position it - // points to. Because the mappings are sorted, we can use binary search to - // find the best mapping. - - if (aNeedle[aLineName] <= 0) { - throw new TypeError('Line must be greater than or equal to 1, got ' - + aNeedle[aLineName]); - } - if (aNeedle[aColumnName] < 0) { - throw new TypeError('Column must be greater than or equal to 0, got ' - + aNeedle[aColumnName]); - } - - return binarySearch.search(aNeedle, aMappings, aComparator, aBias); - }; - -/** - * Compute the last column for each generated mapping. The last column is - * inclusive. - */ -BasicSourceMapConsumer.prototype.computeColumnSpans = - function SourceMapConsumer_computeColumnSpans() { - for (var index = 0; index < this._generatedMappings.length; ++index) { - var mapping = this._generatedMappings[index]; - - // Mappings do not contain a field for the last generated columnt. We - // can come up with an optimistic estimate, however, by assuming that - // mappings are contiguous (i.e. given two consecutive mappings, the - // first mapping ends where the second one starts). - if (index + 1 < this._generatedMappings.length) { - var nextMapping = this._generatedMappings[index + 1]; - - if (mapping.generatedLine === nextMapping.generatedLine) { - mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1; - continue; - } - } - - // The last mapping for each line spans the entire line. - mapping.lastGeneratedColumn = Infinity; - } - }; - -/** - * Returns the original source, line, and column information for the generated - * source's line and column positions provided. The only argument is an object - * with the following properties: - * - * - line: The line number in the generated source. - * - column: The column number in the generated source. - * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or - * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the - * closest element that is smaller than or greater than the one we are - * searching for, respectively, if the exact element cannot be found. - * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'. - * - * and an object is returned with the following properties: - * - * - source: The original source file, or null. - * - line: The line number in the original source, or null. - * - column: The column number in the original source, or null. - * - name: The original identifier, or null. - */ -BasicSourceMapConsumer.prototype.originalPositionFor = - function SourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') - }; - - var index = this._findMapping( - needle, - this._generatedMappings, - "generatedLine", - "generatedColumn", - util.compareByGeneratedPositionsDeflated, - util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND) - ); - - if (index >= 0) { - var mapping = this._generatedMappings[index]; - - if (mapping.generatedLine === needle.generatedLine) { - var source = util.getArg(mapping, 'source', null); - if (source !== null) { - source = this._sources.at(source); - if (this.sourceRoot != null) { - source = util.join(this.sourceRoot, source); - } - } - var name = util.getArg(mapping, 'name', null); - if (name !== null) { - name = this._names.at(name); - } - return { - source: source, - line: util.getArg(mapping, 'originalLine', null), - column: util.getArg(mapping, 'originalColumn', null), - name: name - }; - } - } - - return { - source: null, - line: null, - column: null, - name: null - }; - }; - -/** - * Return true if we have the source content for every source in the source - * map, false otherwise. - */ -BasicSourceMapConsumer.prototype.hasContentsOfAllSources = - function BasicSourceMapConsumer_hasContentsOfAllSources() { - if (!this.sourcesContent) { - return false; - } - return this.sourcesContent.length >= this._sources.size() && - !this.sourcesContent.some(function (sc) { return sc == null; }); - }; - -/** - * Returns the original source content. The only argument is the url of the - * original source file. Returns null if no original source content is - * available. - */ -BasicSourceMapConsumer.prototype.sourceContentFor = - function SourceMapConsumer_sourceContentFor(aSource, nullOnMissing) { - if (!this.sourcesContent) { - return null; - } - - if (this.sourceRoot != null) { - aSource = util.relative(this.sourceRoot, aSource); - } - - if (this._sources.has(aSource)) { - return this.sourcesContent[this._sources.indexOf(aSource)]; - } - - var url; - if (this.sourceRoot != null - && (url = util.urlParse(this.sourceRoot))) { - // XXX: file:// URIs and absolute paths lead to unexpected behavior for - // many users. We can help them out when they expect file:// URIs to - // behave like it would if they were running a local HTTP server. See - // https://bugzilla.mozilla.org/show_bug.cgi?id=885597. - var fileUriAbsPath = aSource.replace(/^file:\/\//, ""); - if (url.scheme == "file" - && this._sources.has(fileUriAbsPath)) { - return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)] - } - - if ((!url.path || url.path == "/") - && this._sources.has("/" + aSource)) { - return this.sourcesContent[this._sources.indexOf("/" + aSource)]; - } - } - - // This function is used recursively from - // IndexedSourceMapConsumer.prototype.sourceContentFor. In that case, we - // don't want to throw if we can't find the source - we just want to - // return null, so we provide a flag to exit gracefully. - if (nullOnMissing) { - return null; - } - else { - throw new Error('"' + aSource + '" is not in the SourceMap.'); - } - }; - -/** - * Returns the generated line and column information for the original source, - * line, and column positions provided. The only argument is an object with - * the following properties: - * - * - source: The filename of the original source. - * - line: The line number in the original source. - * - column: The column number in the original source. - * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or - * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the - * closest element that is smaller than or greater than the one we are - * searching for, respectively, if the exact element cannot be found. - * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'. - * - * and an object is returned with the following properties: - * - * - line: The line number in the generated source, or null. - * - column: The column number in the generated source, or null. - */ -BasicSourceMapConsumer.prototype.generatedPositionFor = - function SourceMapConsumer_generatedPositionFor(aArgs) { - var source = util.getArg(aArgs, 'source'); - if (this.sourceRoot != null) { - source = util.relative(this.sourceRoot, source); - } - if (!this._sources.has(source)) { - return { - line: null, - column: null, - lastColumn: null - }; - } - source = this._sources.indexOf(source); - - var needle = { - source: source, - originalLine: util.getArg(aArgs, 'line'), - originalColumn: util.getArg(aArgs, 'column') - }; - - var index = this._findMapping( - needle, - this._originalMappings, - "originalLine", - "originalColumn", - util.compareByOriginalPositions, - util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND) - ); - - if (index >= 0) { - var mapping = this._originalMappings[index]; - - if (mapping.source === needle.source) { - return { - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null), - lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) - }; - } - } - - return { - line: null, - column: null, - lastColumn: null - }; - }; - -exports.BasicSourceMapConsumer = BasicSourceMapConsumer; - -/** - * An IndexedSourceMapConsumer instance represents a parsed source map which - * we can query for information. It differs from BasicSourceMapConsumer in - * that it takes "indexed" source maps (i.e. ones with a "sections" field) as - * input. - * - * The only parameter is a raw source map (either as a JSON string, or already - * parsed to an object). According to the spec for indexed source maps, they - * have the following attributes: - * - * - version: Which version of the source map spec this map is following. - * - file: Optional. The generated file this source map is associated with. - * - sections: A list of section definitions. - * - * Each value under the "sections" field has two fields: - * - offset: The offset into the original specified at which this section - * begins to apply, defined as an object with a "line" and "column" - * field. - * - map: A source map definition. This source map could also be indexed, - * but doesn't have to be. - * - * Instead of the "map" field, it's also possible to have a "url" field - * specifying a URL to retrieve a source map from, but that's currently - * unsupported. - * - * Here's an example source map, taken from the source map spec[0], but - * modified to omit a section which uses the "url" field. - * - * { - * version : 3, - * file: "app.js", - * sections: [{ - * offset: {line:100, column:10}, - * map: { - * version : 3, - * file: "section.js", - * sources: ["foo.js", "bar.js"], - * names: ["src", "maps", "are", "fun"], - * mappings: "AAAA,E;;ABCDE;" - * } - * }], - * } - * - * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt - */ -function IndexedSourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } - - var version = util.getArg(sourceMap, 'version'); - var sections = util.getArg(sourceMap, 'sections'); - - if (version != this._version) { - throw new Error('Unsupported version: ' + version); - } - - this._sources = new ArraySet(); - this._names = new ArraySet(); - - var lastOffset = { - line: -1, - column: 0 - }; - this._sections = sections.map(function (s) { - if (s.url) { - // The url field will require support for asynchronicity. - // See https://github.com/mozilla/source-map/issues/16 - throw new Error('Support for url field in sections not implemented.'); - } - var offset = util.getArg(s, 'offset'); - var offsetLine = util.getArg(offset, 'line'); - var offsetColumn = util.getArg(offset, 'column'); - - if (offsetLine < lastOffset.line || - (offsetLine === lastOffset.line && offsetColumn < lastOffset.column)) { - throw new Error('Section offsets must be ordered and non-overlapping.'); - } - lastOffset = offset; - - return { - generatedOffset: { - // The offset fields are 0-based, but we use 1-based indices when - // encoding/decoding from VLQ. - generatedLine: offsetLine + 1, - generatedColumn: offsetColumn + 1 - }, - consumer: new SourceMapConsumer(util.getArg(s, 'map')) - } - }); -} - -IndexedSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype); -IndexedSourceMapConsumer.prototype.constructor = SourceMapConsumer; - -/** - * The version of the source mapping spec that we are consuming. - */ -IndexedSourceMapConsumer.prototype._version = 3; - -/** - * The list of original sources. - */ -Object.defineProperty(IndexedSourceMapConsumer.prototype, 'sources', { - get: function () { - var sources = []; - for (var i = 0; i < this._sections.length; i++) { - for (var j = 0; j < this._sections[i].consumer.sources.length; j++) { - sources.push(this._sections[i].consumer.sources[j]); - } - } - return sources; - } -}); - -/** - * Returns the original source, line, and column information for the generated - * source's line and column positions provided. The only argument is an object - * with the following properties: - * - * - line: The line number in the generated source. - * - column: The column number in the generated source. - * - * and an object is returned with the following properties: - * - * - source: The original source file, or null. - * - line: The line number in the original source, or null. - * - column: The column number in the original source, or null. - * - name: The original identifier, or null. - */ -IndexedSourceMapConsumer.prototype.originalPositionFor = - function IndexedSourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') - }; - - // Find the section containing the generated position we're trying to map - // to an original position. - var sectionIndex = binarySearch.search(needle, this._sections, - function(needle, section) { - var cmp = needle.generatedLine - section.generatedOffset.generatedLine; - if (cmp) { - return cmp; - } - - return (needle.generatedColumn - - section.generatedOffset.generatedColumn); - }); - var section = this._sections[sectionIndex]; - - if (!section) { - return { - source: null, - line: null, - column: null, - name: null - }; - } - - return section.consumer.originalPositionFor({ - line: needle.generatedLine - - (section.generatedOffset.generatedLine - 1), - column: needle.generatedColumn - - (section.generatedOffset.generatedLine === needle.generatedLine - ? section.generatedOffset.generatedColumn - 1 - : 0), - bias: aArgs.bias - }); - }; - -/** - * Return true if we have the source content for every source in the source - * map, false otherwise. - */ -IndexedSourceMapConsumer.prototype.hasContentsOfAllSources = - function IndexedSourceMapConsumer_hasContentsOfAllSources() { - return this._sections.every(function (s) { - return s.consumer.hasContentsOfAllSources(); - }); - }; - -/** - * Returns the original source content. The only argument is the url of the - * original source file. Returns null if no original source content is - * available. - */ -IndexedSourceMapConsumer.prototype.sourceContentFor = - function IndexedSourceMapConsumer_sourceContentFor(aSource, nullOnMissing) { - for (var i = 0; i < this._sections.length; i++) { - var section = this._sections[i]; - - var content = section.consumer.sourceContentFor(aSource, true); - if (content) { - return content; - } - } - if (nullOnMissing) { - return null; - } - else { - throw new Error('"' + aSource + '" is not in the SourceMap.'); - } - }; - -/** - * Returns the generated line and column information for the original source, - * line, and column positions provided. The only argument is an object with - * the following properties: - * - * - source: The filename of the original source. - * - line: The line number in the original source. - * - column: The column number in the original source. - * - * and an object is returned with the following properties: - * - * - line: The line number in the generated source, or null. - * - column: The column number in the generated source, or null. - */ -IndexedSourceMapConsumer.prototype.generatedPositionFor = - function IndexedSourceMapConsumer_generatedPositionFor(aArgs) { - for (var i = 0; i < this._sections.length; i++) { - var section = this._sections[i]; - - // Only consider this section if the requested source is in the list of - // sources of the consumer. - if (section.consumer.sources.indexOf(util.getArg(aArgs, 'source')) === -1) { - continue; - } - var generatedPosition = section.consumer.generatedPositionFor(aArgs); - if (generatedPosition) { - var ret = { - line: generatedPosition.line + - (section.generatedOffset.generatedLine - 1), - column: generatedPosition.column + - (section.generatedOffset.generatedLine === generatedPosition.line - ? section.generatedOffset.generatedColumn - 1 - : 0) - }; - return ret; - } - } - - return { - line: null, - column: null - }; - }; - -/** - * Parse the mappings in a string in to a data structure which we can easily - * query (the ordered arrays in the `this.__generatedMappings` and - * `this.__originalMappings` properties). - */ -IndexedSourceMapConsumer.prototype._parseMappings = - function IndexedSourceMapConsumer_parseMappings(aStr, aSourceRoot) { - this.__generatedMappings = []; - this.__originalMappings = []; - for (var i = 0; i < this._sections.length; i++) { - var section = this._sections[i]; - var sectionMappings = section.consumer._generatedMappings; - for (var j = 0; j < sectionMappings.length; j++) { - var mapping = sectionMappings[j]; - - var source = section.consumer._sources.at(mapping.source); - if (section.consumer.sourceRoot !== null) { - source = util.join(section.consumer.sourceRoot, source); - } - this._sources.add(source); - source = this._sources.indexOf(source); - - var name = section.consumer._names.at(mapping.name); - this._names.add(name); - name = this._names.indexOf(name); - - // The mappings coming from the consumer for the section have - // generated positions relative to the start of the section, so we - // need to offset them to be relative to the start of the concatenated - // generated file. - var adjustedMapping = { - source: source, - generatedLine: mapping.generatedLine + - (section.generatedOffset.generatedLine - 1), - generatedColumn: mapping.generatedColumn + - (section.generatedOffset.generatedLine === mapping.generatedLine - ? section.generatedOffset.generatedColumn - 1 - : 0), - originalLine: mapping.originalLine, - originalColumn: mapping.originalColumn, - name: name - }; - - this.__generatedMappings.push(adjustedMapping); - if (typeof adjustedMapping.originalLine === 'number') { - this.__originalMappings.push(adjustedMapping); - } - } - } - - quickSort(this.__generatedMappings, util.compareByGeneratedPositionsDeflated); - quickSort(this.__originalMappings, util.compareByOriginalPositions); - }; - -exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; - - -/***/ }), -/* 816 */ -/***/ (function(module, exports) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -exports.GREATEST_LOWER_BOUND = 1; -exports.LEAST_UPPER_BOUND = 2; - -/** - * Recursive implementation of binary search. - * - * @param aLow Indices here and lower do not contain the needle. - * @param aHigh Indices here and higher do not contain the needle. - * @param aNeedle The element being searched for. - * @param aHaystack The non-empty array being searched. - * @param aCompare Function which takes two elements and returns -1, 0, or 1. - * @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or - * 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the - * closest element that is smaller than or greater than the one we are - * searching for, respectively, if the exact element cannot be found. - */ -function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare, aBias) { - // This function terminates when one of the following is true: - // - // 1. We find the exact element we are looking for. - // - // 2. We did not find the exact element, but we can return the index of - // the next-closest element. - // - // 3. We did not find the exact element, and there is no next-closest - // element than the one we are searching for, so we return -1. - var mid = Math.floor((aHigh - aLow) / 2) + aLow; - var cmp = aCompare(aNeedle, aHaystack[mid], true); - if (cmp === 0) { - // Found the element we are looking for. - return mid; - } - else if (cmp > 0) { - // Our needle is greater than aHaystack[mid]. - if (aHigh - mid > 1) { - // The element is in the upper half. - return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare, aBias); - } - - // The exact needle element was not found in this haystack. Determine if - // we are in termination case (3) or (2) and return the appropriate thing. - if (aBias == exports.LEAST_UPPER_BOUND) { - return aHigh < aHaystack.length ? aHigh : -1; - } else { - return mid; - } - } - else { - // Our needle is less than aHaystack[mid]. - if (mid - aLow > 1) { - // The element is in the lower half. - return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare, aBias); - } - - // we are in termination case (3) or (2) and return the appropriate thing. - if (aBias == exports.LEAST_UPPER_BOUND) { - return mid; - } else { - return aLow < 0 ? -1 : aLow; - } - } -} - -/** - * This is an implementation of binary search which will always try and return - * the index of the closest element if there is no exact hit. This is because - * mappings between original and generated line/col pairs are single points, - * and there is an implicit region between each of them, so a miss just means - * that you aren't on the very start of a region. - * - * @param aNeedle The element you are looking for. - * @param aHaystack The array that is being searched. - * @param aCompare A function which takes the needle and an element in the - * array and returns -1, 0, or 1 depending on whether the needle is less - * than, equal to, or greater than the element, respectively. - * @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or - * 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the - * closest element that is smaller than or greater than the one we are - * searching for, respectively, if the exact element cannot be found. - * Defaults to 'binarySearch.GREATEST_LOWER_BOUND'. - */ -exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { - if (aHaystack.length === 0) { - return -1; - } - - var index = recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, - aCompare, aBias || exports.GREATEST_LOWER_BOUND); - if (index < 0) { - return -1; - } - - // We have found either the exact element, or the next-closest element than - // the one we are searching for. However, there may be more than one such - // element. Make sure we always return the smallest of these. - while (index - 1 >= 0) { - if (aCompare(aHaystack[index], aHaystack[index - 1], true) !== 0) { - break; - } - --index; - } - - return index; -}; - - -/***/ }), -/* 817 */ -/***/ (function(module, exports) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -// It turns out that some (most?) JavaScript engines don't self-host -// `Array.prototype.sort`. This makes sense because C++ will likely remain -// faster than JS when doing raw CPU-intensive sorting. However, when using a -// custom comparator function, calling back and forth between the VM's C++ and -// JIT'd JS is rather slow *and* loses JIT type information, resulting in -// worse generated code for the comparator function than would be optimal. In -// fact, when sorting with a comparator, these costs outweigh the benefits of -// sorting in C++. By using our own JS-implemented Quick Sort (below), we get -// a ~3500ms mean speed-up in `bench/bench.html`. - -/** - * Swap the elements indexed by `x` and `y` in the array `ary`. - * - * @param {Array} ary - * The array. - * @param {Number} x - * The index of the first item. - * @param {Number} y - * The index of the second item. - */ -function swap(ary, x, y) { - var temp = ary[x]; - ary[x] = ary[y]; - ary[y] = temp; -} - -/** - * Returns a random integer within the range `low .. high` inclusive. - * - * @param {Number} low - * The lower bound on the range. - * @param {Number} high - * The upper bound on the range. - */ -function randomIntInRange(low, high) { - return Math.round(low + (Math.random() * (high - low))); -} - -/** - * The Quick Sort algorithm. - * - * @param {Array} ary - * An array to sort. - * @param {function} comparator - * Function to use to compare two items. - * @param {Number} p - * Start index of the array - * @param {Number} r - * End index of the array - */ -function doQuickSort(ary, comparator, p, r) { - // If our lower bound is less than our upper bound, we (1) partition the - // array into two pieces and (2) recurse on each half. If it is not, this is - // the empty array and our base case. - - if (p < r) { - // (1) Partitioning. - // - // The partitioning chooses a pivot between `p` and `r` and moves all - // elements that are less than or equal to the pivot to the before it, and - // all the elements that are greater than it after it. The effect is that - // once partition is done, the pivot is in the exact place it will be when - // the array is put in sorted order, and it will not need to be moved - // again. This runs in O(n) time. - - // Always choose a random pivot so that an input array which is reverse - // sorted does not cause O(n^2) running time. - var pivotIndex = randomIntInRange(p, r); - var i = p - 1; - - swap(ary, pivotIndex, r); - var pivot = ary[r]; - - // Immediately after `j` is incremented in this loop, the following hold - // true: - // - // * Every element in `ary[p .. i]` is less than or equal to the pivot. - // - // * Every element in `ary[i+1 .. j-1]` is greater than the pivot. - for (var j = p; j < r; j++) { - if (comparator(ary[j], pivot) <= 0) { - i += 1; - swap(ary, i, j); - } - } - - swap(ary, i + 1, j); - var q = i + 1; - - // (2) Recurse on each half. - - doQuickSort(ary, comparator, p, q - 1); - doQuickSort(ary, comparator, q + 1, r); - } -} - -/** - * Sort the given array in-place with the given comparator function. - * - * @param {Array} ary - * An array to sort. - * @param {function} comparator - * Function to use to compare two items. - */ -exports.quickSort = function (ary, comparator) { - doQuickSort(ary, comparator, 0, ary.length - 1); -}; - - -/***/ }), -/* 818 */ -/***/ (function(module, exports, __webpack_require__) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var SourceMapGenerator = __webpack_require__(809).SourceMapGenerator; -var util = __webpack_require__(812); - -// Matches a Windows-style `\r\n` newline or a `\n` newline used by all other -// operating systems these days (capturing the result). -var REGEX_NEWLINE = /(\r?\n)/; - -// Newline character code for charCodeAt() comparisons -var NEWLINE_CODE = 10; - -// Private symbol for identifying `SourceNode`s when multiple versions of -// the source-map library are loaded. This MUST NOT CHANGE across -// versions! -var isSourceNode = "$$$isSourceNode$$$"; - -/** - * SourceNodes provide a way to abstract over interpolating/concatenating - * snippets of generated JavaScript source code while maintaining the line and - * column information associated with the original source code. - * - * @param aLine The original line number. - * @param aColumn The original column number. - * @param aSource The original source's filename. - * @param aChunks Optional. An array of strings which are snippets of - * generated JS, or other SourceNodes. - * @param aName The original identifier. - */ -function SourceNode(aLine, aColumn, aSource, aChunks, aName) { - this.children = []; - this.sourceContents = {}; - this.line = aLine == null ? null : aLine; - this.column = aColumn == null ? null : aColumn; - this.source = aSource == null ? null : aSource; - this.name = aName == null ? null : aName; - this[isSourceNode] = true; - if (aChunks != null) this.add(aChunks); -} - -/** - * Creates a SourceNode from generated code and a SourceMapConsumer. - * - * @param aGeneratedCode The generated code - * @param aSourceMapConsumer The SourceMap for the generated code - * @param aRelativePath Optional. The path that relative sources in the - * SourceMapConsumer should be relative to. - */ -SourceNode.fromStringWithSourceMap = - function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) { - // The SourceNode we want to fill with the generated code - // and the SourceMap - var node = new SourceNode(); - - // All even indices of this array are one line of the generated code, - // while all odd indices are the newlines between two adjacent lines - // (since `REGEX_NEWLINE` captures its match). - // Processed fragments are accessed by calling `shiftNextLine`. - var remainingLines = aGeneratedCode.split(REGEX_NEWLINE); - var remainingLinesIndex = 0; - var shiftNextLine = function() { - var lineContents = getNextLine(); - // The last line of a file might not have a newline. - var newLine = getNextLine() || ""; - return lineContents + newLine; - - function getNextLine() { - return remainingLinesIndex < remainingLines.length ? - remainingLines[remainingLinesIndex++] : undefined; - } - }; - - // We need to remember the position of "remainingLines" - var lastGeneratedLine = 1, lastGeneratedColumn = 0; - - // The generate SourceNodes we need a code range. - // To extract it current and last mapping is used. - // Here we store the last mapping. - var lastMapping = null; - - aSourceMapConsumer.eachMapping(function (mapping) { - if (lastMapping !== null) { - // We add the code from "lastMapping" to "mapping": - // First check if there is a new line in between. - if (lastGeneratedLine < mapping.generatedLine) { - // Associate first line with "lastMapping" - addMappingWithCode(lastMapping, shiftNextLine()); - lastGeneratedLine++; - lastGeneratedColumn = 0; - // The remaining code is added without mapping - } else { - // There is no new line in between. - // Associate the code between "lastGeneratedColumn" and - // "mapping.generatedColumn" with "lastMapping" - var nextLine = remainingLines[remainingLinesIndex]; - var code = nextLine.substr(0, mapping.generatedColumn - - lastGeneratedColumn); - remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn - - lastGeneratedColumn); - lastGeneratedColumn = mapping.generatedColumn; - addMappingWithCode(lastMapping, code); - // No more remaining code, continue - lastMapping = mapping; - return; - } - } - // We add the generated code until the first mapping - // to the SourceNode without any mapping. - // Each line is added as separate string. - while (lastGeneratedLine < mapping.generatedLine) { - node.add(shiftNextLine()); - lastGeneratedLine++; - } - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[remainingLinesIndex]; - node.add(nextLine.substr(0, mapping.generatedColumn)); - remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - lastMapping = mapping; - }, this); - // We have processed all mappings. - if (remainingLinesIndex < remainingLines.length) { - if (lastMapping) { - // Associate the remaining code in the current line with "lastMapping" - addMappingWithCode(lastMapping, shiftNextLine()); - } - // and add the remaining lines without any mapping - node.add(remainingLines.splice(remainingLinesIndex).join("")); - } - - // Copy sourcesContent into SourceNode - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content != null) { - if (aRelativePath != null) { - sourceFile = util.join(aRelativePath, sourceFile); - } - node.setSourceContent(sourceFile, content); - } - }); - - return node; - - function addMappingWithCode(mapping, code) { - if (mapping === null || mapping.source === undefined) { - node.add(code); - } else { - var source = aRelativePath - ? util.join(aRelativePath, mapping.source) - : mapping.source; - node.add(new SourceNode(mapping.originalLine, - mapping.originalColumn, - source, - code, - mapping.name)); - } - } - }; - -/** - * Add a chunk of generated JS to this source node. - * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. - */ -SourceNode.prototype.add = function SourceNode_add(aChunk) { - if (Array.isArray(aChunk)) { - aChunk.forEach(function (chunk) { - this.add(chunk); - }, this); - } - else if (aChunk[isSourceNode] || typeof aChunk === "string") { - if (aChunk) { - this.children.push(aChunk); - } - } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); - } - return this; -}; - -/** - * Add a chunk of generated JS to the beginning of this source node. - * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. - */ -SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { - if (Array.isArray(aChunk)) { - for (var i = aChunk.length-1; i >= 0; i--) { - this.prepend(aChunk[i]); - } - } - else if (aChunk[isSourceNode] || typeof aChunk === "string") { - this.children.unshift(aChunk); - } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); - } - return this; -}; - -/** - * Walk over the tree of JS snippets in this node and its children. The - * walking function is called once for each snippet of JS and is passed that - * snippet and the its original associated source's line/column location. - * - * @param aFn The traversal function. - */ -SourceNode.prototype.walk = function SourceNode_walk(aFn) { - var chunk; - for (var i = 0, len = this.children.length; i < len; i++) { - chunk = this.children[i]; - if (chunk[isSourceNode]) { - chunk.walk(aFn); - } - else { - if (chunk !== '') { - aFn(chunk, { source: this.source, - line: this.line, - column: this.column, - name: this.name }); - } - } - } -}; - -/** - * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between - * each of `this.children`. - * - * @param aSep The separator. - */ -SourceNode.prototype.join = function SourceNode_join(aSep) { - var newChildren; - var i; - var len = this.children.length; - if (len > 0) { - newChildren = []; - for (i = 0; i < len-1; i++) { - newChildren.push(this.children[i]); - newChildren.push(aSep); - } - newChildren.push(this.children[i]); - this.children = newChildren; - } - return this; -}; - -/** - * Call String.prototype.replace on the very right-most source snippet. Useful - * for trimming whitespace from the end of a source node, etc. - * - * @param aPattern The pattern to replace. - * @param aReplacement The thing to replace the pattern with. - */ -SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { - var lastChild = this.children[this.children.length - 1]; - if (lastChild[isSourceNode]) { - lastChild.replaceRight(aPattern, aReplacement); - } - else if (typeof lastChild === 'string') { - this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); - } - else { - this.children.push(''.replace(aPattern, aReplacement)); - } - return this; -}; - -/** - * Set the source content for a source file. This will be added to the SourceMapGenerator - * in the sourcesContent field. - * - * @param aSourceFile The filename of the source file - * @param aSourceContent The content of the source file - */ -SourceNode.prototype.setSourceContent = - function SourceNode_setSourceContent(aSourceFile, aSourceContent) { - this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; - }; - -/** - * Walk over the tree of SourceNodes. The walking function is called for each - * source file content and is passed the filename and source content. - * - * @param aFn The traversal function. - */ -SourceNode.prototype.walkSourceContents = - function SourceNode_walkSourceContents(aFn) { - for (var i = 0, len = this.children.length; i < len; i++) { - if (this.children[i][isSourceNode]) { - this.children[i].walkSourceContents(aFn); - } - } - - var sources = Object.keys(this.sourceContents); - for (var i = 0, len = sources.length; i < len; i++) { - aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); - } - }; - -/** - * Return the string representation of this source node. Walks over the tree - * and concatenates all the various snippets together to one string. - */ -SourceNode.prototype.toString = function SourceNode_toString() { - var str = ""; - this.walk(function (chunk) { - str += chunk; - }); - return str; -}; - -/** - * Returns the string representation of this source node along with a source - * map. - */ -SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { - var generated = { - code: "", - line: 1, - column: 0 - }; - var map = new SourceMapGenerator(aArgs); - var sourceMappingActive = false; - var lastOriginalSource = null; - var lastOriginalLine = null; - var lastOriginalColumn = null; - var lastOriginalName = null; - this.walk(function (chunk, original) { - generated.code += chunk; - if (original.source !== null - && original.line !== null - && original.column !== null) { - if(lastOriginalSource !== original.source - || lastOriginalLine !== original.line - || lastOriginalColumn !== original.column - || lastOriginalName !== original.name) { - map.addMapping({ - source: original.source, - original: { - line: original.line, - column: original.column - }, - generated: { - line: generated.line, - column: generated.column - }, - name: original.name - }); - } - lastOriginalSource = original.source; - lastOriginalLine = original.line; - lastOriginalColumn = original.column; - lastOriginalName = original.name; - sourceMappingActive = true; - } else if (sourceMappingActive) { - map.addMapping({ - generated: { - line: generated.line, - column: generated.column - } - }); - lastOriginalSource = null; - sourceMappingActive = false; - } - for (var idx = 0, length = chunk.length; idx < length; idx++) { - if (chunk.charCodeAt(idx) === NEWLINE_CODE) { - generated.line++; - generated.column = 0; - // Mappings end at eol - if (idx + 1 === length) { - lastOriginalSource = null; - sourceMappingActive = false; - } else if (sourceMappingActive) { - map.addMapping({ - source: original.source, - original: { - line: original.line, - column: original.column - }, - generated: { - line: generated.line, - column: generated.column - }, - name: original.name - }); - } - } else { - generated.column++; - } - } - }); - this.walkSourceContents(function (sourceFile, sourceContent) { - map.setSourceContent(sourceFile, sourceContent); - }); - - return { code: generated.code, map: map }; -}; - -exports.SourceNode = SourceNode; - - -/***/ }), -/* 819 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2014, 2015, 2016, 2017 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) - -var sourceMappingURL = __webpack_require__(820) -var resolveUrl = __webpack_require__(821) -var decodeUriComponent = __webpack_require__(822) -var urix = __webpack_require__(824) -var atob = __webpack_require__(825) - - - -function callbackAsync(callback, error, result) { - setImmediate(function() { callback(error, result) }) -} - -function parseMapToJSON(string, data) { - try { - return JSON.parse(string.replace(/^\)\]\}'/, "")) - } catch (error) { - error.sourceMapData = data - throw error - } -} - -function readSync(read, url, data) { - var readUrl = decodeUriComponent(url) - try { - return String(read(readUrl)) - } catch (error) { - error.sourceMapData = data - throw error - } -} - - - -function resolveSourceMap(code, codeUrl, read, callback) { - var mapData - try { - mapData = resolveSourceMapHelper(code, codeUrl) - } catch (error) { - return callbackAsync(callback, error) - } - if (!mapData || mapData.map) { - return callbackAsync(callback, null, mapData) - } - var readUrl = decodeUriComponent(mapData.url) - read(readUrl, function(error, result) { - if (error) { - error.sourceMapData = mapData - return callback(error) - } - mapData.map = String(result) - try { - mapData.map = parseMapToJSON(mapData.map, mapData) - } catch (error) { - return callback(error) - } - callback(null, mapData) - }) -} - -function resolveSourceMapSync(code, codeUrl, read) { - var mapData = resolveSourceMapHelper(code, codeUrl) - if (!mapData || mapData.map) { - return mapData - } - mapData.map = readSync(read, mapData.url, mapData) - mapData.map = parseMapToJSON(mapData.map, mapData) - return mapData -} - -var dataUriRegex = /^data:([^,;]*)(;[^,;]*)*(?:,(.*))?$/ -var jsonMimeTypeRegex = /^(?:application|text)\/json$/ - -function resolveSourceMapHelper(code, codeUrl) { - codeUrl = urix(codeUrl) - - var url = sourceMappingURL.getFrom(code) - if (!url) { - return null - } - - var dataUri = url.match(dataUriRegex) - if (dataUri) { - var mimeType = dataUri[1] - var lastParameter = dataUri[2] || "" - var encoded = dataUri[3] || "" - var data = { - sourceMappingURL: url, - url: null, - sourcesRelativeTo: codeUrl, - map: encoded - } - if (!jsonMimeTypeRegex.test(mimeType)) { - var error = new Error("Unuseful data uri mime type: " + (mimeType || "text/plain")) - error.sourceMapData = data - throw error - } - data.map = parseMapToJSON( - lastParameter === ";base64" ? atob(encoded) : decodeURIComponent(encoded), - data - ) - return data - } - - var mapUrl = resolveUrl(codeUrl, url) - return { - sourceMappingURL: url, - url: mapUrl, - sourcesRelativeTo: mapUrl, - map: null - } -} - - - -function resolveSources(map, mapUrl, read, options, callback) { - if (typeof options === "function") { - callback = options - options = {} - } - var pending = map.sources ? map.sources.length : 0 - var result = { - sourcesResolved: [], - sourcesContent: [] - } - - if (pending === 0) { - callbackAsync(callback, null, result) - return - } - - var done = function() { - pending-- - if (pending === 0) { - callback(null, result) - } - } - - resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) { - result.sourcesResolved[index] = fullUrl - if (typeof sourceContent === "string") { - result.sourcesContent[index] = sourceContent - callbackAsync(done, null) - } else { - var readUrl = decodeUriComponent(fullUrl) - read(readUrl, function(error, source) { - result.sourcesContent[index] = error ? error : String(source) - done() - }) - } - }) -} - -function resolveSourcesSync(map, mapUrl, read, options) { - var result = { - sourcesResolved: [], - sourcesContent: [] - } - - if (!map.sources || map.sources.length === 0) { - return result - } - - resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) { - result.sourcesResolved[index] = fullUrl - if (read !== null) { - if (typeof sourceContent === "string") { - result.sourcesContent[index] = sourceContent - } else { - var readUrl = decodeUriComponent(fullUrl) - try { - result.sourcesContent[index] = String(read(readUrl)) - } catch (error) { - result.sourcesContent[index] = error - } - } - } - }) - - return result -} - -var endingSlash = /\/?$/ - -function resolveSourcesHelper(map, mapUrl, options, fn) { - options = options || {} - mapUrl = urix(mapUrl) - var fullUrl - var sourceContent - var sourceRoot - for (var index = 0, len = map.sources.length; index < len; index++) { - sourceRoot = null - if (typeof options.sourceRoot === "string") { - sourceRoot = options.sourceRoot - } else if (typeof map.sourceRoot === "string" && options.sourceRoot !== false) { - sourceRoot = map.sourceRoot - } - // If the sourceRoot is the empty string, it is equivalent to not setting - // the property at all. - if (sourceRoot === null || sourceRoot === '') { - fullUrl = resolveUrl(mapUrl, map.sources[index]) - } else { - // Make sure that the sourceRoot ends with a slash, so that `/scripts/subdir` becomes - // `/scripts/subdir/`, not `/scripts/`. Pointing to a file as source root - // does not make sense. - fullUrl = resolveUrl(mapUrl, sourceRoot.replace(endingSlash, "/"), map.sources[index]) - } - sourceContent = (map.sourcesContent || [])[index] - fn(fullUrl, sourceContent, index) - } -} - - - -function resolve(code, codeUrl, read, options, callback) { - if (typeof options === "function") { - callback = options - options = {} - } - if (code === null) { - var mapUrl = codeUrl - var data = { - sourceMappingURL: null, - url: mapUrl, - sourcesRelativeTo: mapUrl, - map: null - } - var readUrl = decodeUriComponent(mapUrl) - read(readUrl, function(error, result) { - if (error) { - error.sourceMapData = data - return callback(error) - } - data.map = String(result) - try { - data.map = parseMapToJSON(data.map, data) - } catch (error) { - return callback(error) - } - _resolveSources(data) - }) - } else { - resolveSourceMap(code, codeUrl, read, function(error, mapData) { - if (error) { - return callback(error) - } - if (!mapData) { - return callback(null, null) - } - _resolveSources(mapData) - }) - } - - function _resolveSources(mapData) { - resolveSources(mapData.map, mapData.sourcesRelativeTo, read, options, function(error, result) { - if (error) { - return callback(error) - } - mapData.sourcesResolved = result.sourcesResolved - mapData.sourcesContent = result.sourcesContent - callback(null, mapData) - }) - } -} - -function resolveSync(code, codeUrl, read, options) { - var mapData - if (code === null) { - var mapUrl = codeUrl - mapData = { - sourceMappingURL: null, - url: mapUrl, - sourcesRelativeTo: mapUrl, - map: null - } - mapData.map = readSync(read, mapUrl, mapData) - mapData.map = parseMapToJSON(mapData.map, mapData) - } else { - mapData = resolveSourceMapSync(code, codeUrl, read) - if (!mapData) { - return null - } - } - var result = resolveSourcesSync(mapData.map, mapData.sourcesRelativeTo, read, options) - mapData.sourcesResolved = result.sourcesResolved - mapData.sourcesContent = result.sourcesContent - return mapData -} - - - -module.exports = { - resolveSourceMap: resolveSourceMap, - resolveSourceMapSync: resolveSourceMapSync, - resolveSources: resolveSources, - resolveSourcesSync: resolveSourcesSync, - resolve: resolve, - resolveSync: resolveSync, - parseMapToJSON: parseMapToJSON -} - - -/***/ }), -/* 820 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) - -void (function(root, factory) { - if (true) { - !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), - __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? - (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : - __WEBPACK_AMD_DEFINE_FACTORY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)) - } else {} -}(this, function() { - - var innerRegex = /[#@] sourceMappingURL=([^\s'"]*)/ - - var regex = RegExp( - "(?:" + - "/\\*" + - "(?:\\s*\r?\n(?://)?)?" + - "(?:" + innerRegex.source + ")" + - "\\s*" + - "\\*/" + - "|" + - "//(?:" + innerRegex.source + ")" + - ")" + - "\\s*" - ) - - return { - - regex: regex, - _innerRegex: innerRegex, - - getFrom: function(code) { - var match = code.match(regex) - return (match ? match[1] || match[2] || "" : null) - }, - - existsIn: function(code) { - return regex.test(code) - }, - - removeFrom: function(code) { - return code.replace(regex, "") - }, - - insertBefore: function(code, string) { - var match = code.match(regex) - if (match) { - return code.slice(0, match.index) + string + code.slice(match.index) - } else { - return code + string - } - } - } - -})); - - -/***/ }), -/* 821 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2014 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) - -var url = __webpack_require__(454) - -function resolveUrl(/* ...urls */) { - return Array.prototype.reduce.call(arguments, function(resolved, nextUrl) { - return url.resolve(resolved, nextUrl) - }) -} - -module.exports = resolveUrl - - -/***/ }), -/* 822 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2017 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) - -var decodeUriComponent = __webpack_require__(823) - -function customDecodeUriComponent(string) { - // `decodeUriComponent` turns `+` into ` `, but that's not wanted. - return decodeUriComponent(string.replace(/\+/g, "%2B")) -} - -module.exports = customDecodeUriComponent - - -/***/ }), -/* 823 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var token = '%[a-f0-9]{2}'; -var singleMatcher = new RegExp(token, 'gi'); -var multiMatcher = new RegExp('(' + token + ')+', 'gi'); - -function decodeComponents(components, split) { - try { - // Try to decode the entire string first - return decodeURIComponent(components.join('')); - } catch (err) { - // Do nothing - } - - if (components.length === 1) { - return components; - } - - split = split || 1; - - // Split the array in 2 parts - var left = components.slice(0, split); - var right = components.slice(split); - - return Array.prototype.concat.call([], decodeComponents(left), decodeComponents(right)); -} - -function decode(input) { - try { - return decodeURIComponent(input); - } catch (err) { - var tokens = input.match(singleMatcher); - - for (var i = 1; i < tokens.length; i++) { - input = decodeComponents(tokens, i).join(''); - - tokens = input.match(singleMatcher); - } - - return input; - } -} - -function customDecodeURIComponent(input) { - // Keep track of all the replacements and prefill the map with the `BOM` - var replaceMap = { - '%FE%FF': '\uFFFD\uFFFD', - '%FF%FE': '\uFFFD\uFFFD' - }; - - var match = multiMatcher.exec(input); - while (match) { - try { - // Decode as big chunks as possible - replaceMap[match[0]] = decodeURIComponent(match[0]); - } catch (err) { - var result = decode(match[0]); - - if (result !== match[0]) { - replaceMap[match[0]] = result; - } - } - - match = multiMatcher.exec(input); - } - - // Add `%C2` at the end of the map to make sure it does not replace the combinator before everything else - replaceMap['%C2'] = '\uFFFD'; - - var entries = Object.keys(replaceMap); - - for (var i = 0; i < entries.length; i++) { - // Replace all decoded components - var key = entries[i]; - input = input.replace(new RegExp(key, 'g'), replaceMap[key]); - } - - return input; -} - -module.exports = function (encodedURI) { - if (typeof encodedURI !== 'string') { - throw new TypeError('Expected `encodedURI` to be of type `string`, got `' + typeof encodedURI + '`'); - } - - try { - encodedURI = encodedURI.replace(/\+/g, ' '); - - // Try the built in decoder first - return decodeURIComponent(encodedURI); - } catch (err) { - // Fallback to a more advanced decoder - return customDecodeURIComponent(encodedURI); - } -}; - - -/***/ }), -/* 824 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2014 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) - -var path = __webpack_require__(16) - -"use strict" - -function urix(aPath) { - if (path.sep === "\\") { - return aPath - .replace(/\\/g, "/") - .replace(/^[a-z]:\/?/i, "/") - } - return aPath -} - -module.exports = urix - - -/***/ }), -/* 825 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -function atob(str) { - return Buffer.from(str, 'base64').toString('binary'); -} - -module.exports = atob.atob = atob; - - -/***/ }), -/* 826 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var fs = __webpack_require__(23); -var path = __webpack_require__(16); -var define = __webpack_require__(730); -var utils = __webpack_require__(807); - -/** - * Expose `mixin()`. - * This code is based on `source-maps-support.js` in reworkcss/css - * https://github.com/reworkcss/css/blob/master/lib/stringify/source-map-support.js - * Copyright (c) 2012 TJ Holowaychuk - */ - -module.exports = mixin; - -/** - * Mixin source map support into `compiler`. - * - * @param {Object} `compiler` - * @api public - */ - -function mixin(compiler) { - define(compiler, '_comment', compiler.comment); - compiler.map = new utils.SourceMap.SourceMapGenerator(); - compiler.position = { line: 1, column: 1 }; - compiler.content = {}; - compiler.files = {}; - - for (var key in exports) { - define(compiler, key, exports[key]); - } -} - -/** - * Update position. - * - * @param {String} str - */ - -exports.updatePosition = function(str) { - var lines = str.match(/\n/g); - if (lines) this.position.line += lines.length; - var i = str.lastIndexOf('\n'); - this.position.column = ~i ? str.length - i : this.position.column + str.length; -}; - -/** - * Emit `str` with `position`. - * - * @param {String} str - * @param {Object} [pos] - * @return {String} - */ - -exports.emit = function(str, node) { - var position = node.position || {}; - var source = position.source; - if (source) { - if (position.filepath) { - source = utils.unixify(position.filepath); - } - - this.map.addMapping({ - source: source, - generated: { - line: this.position.line, - column: Math.max(this.position.column - 1, 0) - }, - original: { - line: position.start.line, - column: position.start.column - 1 - } - }); - - if (position.content) { - this.addContent(source, position); - } - if (position.filepath) { - this.addFile(source, position); - } - - this.updatePosition(str); - this.output += str; - } - return str; -}; - -/** - * Adds a file to the source map output if it has not already been added - * @param {String} `file` - * @param {Object} `pos` - */ - -exports.addFile = function(file, position) { - if (typeof position.content !== 'string') return; - if (Object.prototype.hasOwnProperty.call(this.files, file)) return; - this.files[file] = position.content; -}; - -/** - * Adds a content source to the source map output if it has not already been added - * @param {String} `source` - * @param {Object} `position` - */ - -exports.addContent = function(source, position) { - if (typeof position.content !== 'string') return; - if (Object.prototype.hasOwnProperty.call(this.content, source)) return; - this.map.setSourceContent(source, position.content); -}; - -/** - * Applies any original source maps to the output and embeds the source file - * contents in the source map. - */ - -exports.applySourceMaps = function() { - Object.keys(this.files).forEach(function(file) { - var content = this.files[file]; - this.map.setSourceContent(file, content); - - if (this.options.inputSourcemaps === true) { - var originalMap = utils.sourceMapResolve.resolveSync(content, file, fs.readFileSync); - if (originalMap) { - var map = new utils.SourceMap.SourceMapConsumer(originalMap.map); - var relativeTo = originalMap.sourcesRelativeTo; - this.map.applySourceMap(map, file, utils.unixify(path.dirname(relativeTo))); - } - } - }, this); -}; - -/** - * Process comments, drops sourceMap comments. - * @param {Object} node - */ - -exports.comment = function(node) { - if (/^# sourceMappingURL=/.test(node.comment)) { - return this.emit('', node.position); - } - return this._comment(node); -}; - - -/***/ }), -/* 827 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var use = __webpack_require__(799); -var util = __webpack_require__(29); -var Cache = __webpack_require__(828); -var define = __webpack_require__(730); -var debug = __webpack_require__(801)('snapdragon:parser'); -var Position = __webpack_require__(829); -var utils = __webpack_require__(807); - -/** - * Create a new `Parser` with the given `input` and `options`. - * @param {String} `input` - * @param {Object} `options` - * @api public - */ - -function Parser(options) { - debug('initializing', __filename); - this.options = utils.extend({source: 'string'}, options); - this.init(this.options); - use(this); -} - -/** - * Prototype methods - */ - -Parser.prototype = { - constructor: Parser, - - init: function(options) { - this.orig = ''; - this.input = ''; - this.parsed = ''; - - this.column = 1; - this.line = 1; - - this.regex = new Cache(); - this.errors = this.errors || []; - this.parsers = this.parsers || {}; - this.types = this.types || []; - this.sets = this.sets || {}; - this.fns = this.fns || []; - this.currentType = 'root'; - - var pos = this.position(); - this.bos = pos({type: 'bos', val: ''}); - - this.ast = { - type: 'root', - errors: this.errors, - nodes: [this.bos] - }; - - define(this.bos, 'parent', this.ast); - this.nodes = [this.ast]; - - this.count = 0; - this.setCount = 0; - this.stack = []; - }, - - /** - * Throw a formatted error with the cursor column and `msg`. - * @param {String} `msg` Message to use in the Error. - */ - - error: function(msg, node) { - var pos = node.position || {start: {column: 0, line: 0}}; - var line = pos.start.line; - var column = pos.start.column; - var source = this.options.source; - - var message = source + ' : ' + msg; - var err = new Error(message); - err.source = source; - err.reason = msg; - err.pos = pos; - - if (this.options.silent) { - this.errors.push(err); - } else { - throw err; - } - }, - - /** - * Define a non-enumberable property on the `Parser` instance. - * - * ```js - * parser.define('foo', 'bar'); - * ``` - * @name .define - * @param {String} `key` propery name - * @param {any} `val` property value - * @return {Object} Returns the Parser instance for chaining. - * @api public - */ - - define: function(key, val) { - define(this, key, val); - return this; - }, - - /** - * Mark position and patch `node.position`. - */ - - position: function() { - var start = { line: this.line, column: this.column }; - var self = this; - - return function(node) { - define(node, 'position', new Position(start, self)); - return node; - }; - }, - - /** - * Set parser `name` with the given `fn` - * @param {String} `name` - * @param {Function} `fn` - * @api public - */ - - set: function(type, fn) { - if (this.types.indexOf(type) === -1) { - this.types.push(type); - } - this.parsers[type] = fn.bind(this); - return this; - }, - - /** - * Get parser `name` - * @param {String} `name` - * @api public - */ - - get: function(name) { - return this.parsers[name]; - }, - - /** - * Push a `token` onto the `type` stack. - * - * @param {String} `type` - * @return {Object} `token` - * @api public - */ - - push: function(type, token) { - this.sets[type] = this.sets[type] || []; - this.count++; - this.stack.push(token); - return this.sets[type].push(token); - }, - - /** - * Pop a token off of the `type` stack - * @param {String} `type` - * @returns {Object} Returns a token - * @api public - */ - - pop: function(type) { - this.sets[type] = this.sets[type] || []; - this.count--; - this.stack.pop(); - return this.sets[type].pop(); - }, - - /** - * Return true if inside a `stack` node. Types are `braces`, `parens` or `brackets`. - * - * @param {String} `type` - * @return {Boolean} - * @api public - */ - - isInside: function(type) { - this.sets[type] = this.sets[type] || []; - return this.sets[type].length > 0; - }, - - /** - * Return true if `node` is the given `type`. - * - * ```js - * parser.isType(node, 'brace'); - * ``` - * @param {Object} `node` - * @param {String} `type` - * @return {Boolean} - * @api public - */ - - isType: function(node, type) { - return node && node.type === type; - }, - - /** - * Get the previous AST node - * @return {Object} - */ - - prev: function(n) { - return this.stack.length > 0 - ? utils.last(this.stack, n) - : utils.last(this.nodes, n); - }, - - /** - * Update line and column based on `str`. - */ - - consume: function(len) { - this.input = this.input.substr(len); - }, - - /** - * Update column based on `str`. - */ - - updatePosition: function(str, len) { - var lines = str.match(/\n/g); - if (lines) this.line += lines.length; - var i = str.lastIndexOf('\n'); - this.column = ~i ? len - i : this.column + len; - this.parsed += str; - this.consume(len); - }, - - /** - * Match `regex`, return captures, and update the cursor position by `match[0]` length. - * @param {RegExp} `regex` - * @return {Object} - */ - - match: function(regex) { - var m = regex.exec(this.input); - if (m) { - this.updatePosition(m[0], m[0].length); - return m; - } - }, - - /** - * Capture `type` with the given regex. - * @param {String} `type` - * @param {RegExp} `regex` - * @return {Function} - */ - - capture: function(type, regex) { - if (typeof regex === 'function') { - return this.set.apply(this, arguments); - } - - this.regex.set(type, regex); - this.set(type, function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(regex); - if (!m || !m[0]) return; - - var prev = this.prev(); - var node = pos({ - type: type, - val: m[0], - parsed: parsed, - rest: this.input - }); - - if (m[1]) { - node.inner = m[1]; - } - - define(node, 'inside', this.stack.length > 0); - define(node, 'parent', prev); - prev.nodes.push(node); - }.bind(this)); - return this; - }, - - /** - * Create a parser with open and close for parens, - * brackets or braces - */ - - capturePair: function(type, openRegex, closeRegex, fn) { - this.sets[type] = this.sets[type] || []; - - /** - * Open - */ - - this.set(type + '.open', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(openRegex); - if (!m || !m[0]) return; - - var val = m[0]; - this.setCount++; - this.specialChars = true; - var open = pos({ - type: type + '.open', - val: val, - rest: this.input - }); - - if (typeof m[1] !== 'undefined') { - open.inner = m[1]; - } - - var prev = this.prev(); - var node = pos({ - type: type, - nodes: [open] - }); - - define(node, 'rest', this.input); - define(node, 'parsed', parsed); - define(node, 'prefix', m[1]); - define(node, 'parent', prev); - define(open, 'parent', node); - - if (typeof fn === 'function') { - fn.call(this, open, node); - } - - this.push(type, node); - prev.nodes.push(node); - }); - - /** - * Close - */ - - this.set(type + '.close', function() { - var pos = this.position(); - var m = this.match(closeRegex); - if (!m || !m[0]) return; - - var parent = this.pop(type); - var node = pos({ - type: type + '.close', - rest: this.input, - suffix: m[1], - val: m[0] - }); - - if (!this.isType(parent, type)) { - if (this.options.strict) { - throw new Error('missing opening "' + type + '"'); - } - - this.setCount--; - node.escaped = true; - return node; - } - - if (node.suffix === '\\') { - parent.escaped = true; - node.escaped = true; - } - - parent.nodes.push(node); - define(node, 'parent', parent); - }); - - return this; - }, - - /** - * Capture end-of-string - */ - - eos: function() { - var pos = this.position(); - if (this.input) return; - var prev = this.prev(); - - while (prev.type !== 'root' && !prev.visited) { - if (this.options.strict === true) { - throw new SyntaxError('invalid syntax:' + util.inspect(prev, null, 2)); - } - - if (!hasDelims(prev)) { - prev.parent.escaped = true; - prev.escaped = true; - } - - visit(prev, function(node) { - if (!hasDelims(node.parent)) { - node.parent.escaped = true; - node.escaped = true; - } - }); - - prev = prev.parent; - } - - var tok = pos({ - type: 'eos', - val: this.append || '' - }); - - define(tok, 'parent', this.ast); - return tok; - }, - - /** - * Run parsers to advance the cursor position - */ - - next: function() { - var parsed = this.parsed; - var len = this.types.length; - var idx = -1; - var tok; - - while (++idx < len) { - if ((tok = this.parsers[this.types[idx]].call(this))) { - define(tok, 'rest', this.input); - define(tok, 'parsed', parsed); - this.last = tok; - return tok; - } - } - }, - - /** - * Parse the given string. - * @return {Array} - */ - - parse: function(input) { - if (typeof input !== 'string') { - throw new TypeError('expected a string'); - } - - this.init(this.options); - this.orig = input; - this.input = input; - var self = this; - - function parse() { - // check input before calling `.next()` - input = self.input; - - // get the next AST ndoe - var node = self.next(); - if (node) { - var prev = self.prev(); - if (prev) { - define(node, 'parent', prev); - if (prev.nodes) { - prev.nodes.push(node); - } - } - - if (self.sets.hasOwnProperty(prev.type)) { - self.currentType = prev.type; - } - } - - // if we got here but input is not changed, throw an error - if (self.input && input === self.input) { - throw new Error('no parsers registered for: "' + self.input.slice(0, 5) + '"'); - } - } - - while (this.input) parse(); - if (this.stack.length && this.options.strict) { - var node = this.stack.pop(); - throw this.error('missing opening ' + node.type + ': "' + this.orig + '"'); - } - - var eos = this.eos(); - var tok = this.prev(); - if (tok.type !== 'eos') { - this.ast.nodes.push(eos); - } - - return this.ast; - } -}; - -/** - * Visit `node` with the given `fn` - */ - -function visit(node, fn) { - if (!node.visited) { - define(node, 'visited', true); - return node.nodes ? mapVisit(node.nodes, fn) : fn(node); - } - return node; -} - -/** - * Map visit over array of `nodes`. - */ - -function mapVisit(nodes, fn) { - var len = nodes.length; - var idx = -1; - while (++idx < len) { - visit(nodes[idx], fn); - } -} - -function hasOpen(node) { - return node.nodes && node.nodes[0].type === (node.type + '.open'); -} - -function hasClose(node) { - return node.nodes && utils.last(node.nodes).type === (node.type + '.close'); -} - -function hasDelims(node) { - return hasOpen(node) && hasClose(node); -} - -/** - * Expose `Parser` - */ - -module.exports = Parser; - - -/***/ }), -/* 828 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * map-cache - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var hasOwn = Object.prototype.hasOwnProperty; - -/** - * Expose `MapCache` - */ - -module.exports = MapCache; - -/** - * Creates a cache object to store key/value pairs. - * - * ```js - * var cache = new MapCache(); - * ``` - * - * @api public - */ - -function MapCache(data) { - this.__data__ = data || {}; -} - -/** - * Adds `value` to `key` on the cache. - * - * ```js - * cache.set('foo', 'bar'); - * ``` - * - * @param {String} `key` The key of the value to cache. - * @param {*} `value` The value to cache. - * @returns {Object} Returns the `Cache` object for chaining. - * @api public - */ - -MapCache.prototype.set = function mapSet(key, value) { - if (key !== '__proto__') { - this.__data__[key] = value; - } - return this; -}; - -/** - * Gets the cached value for `key`. - * - * ```js - * cache.get('foo'); - * //=> 'bar' - * ``` - * - * @param {String} `key` The key of the value to get. - * @returns {*} Returns the cached value. - * @api public - */ - -MapCache.prototype.get = function mapGet(key) { - return key === '__proto__' ? undefined : this.__data__[key]; -}; - -/** - * Checks if a cached value for `key` exists. - * - * ```js - * cache.has('foo'); - * //=> true - * ``` - * - * @param {String} `key` The key of the entry to check. - * @returns {Boolean} Returns `true` if an entry for `key` exists, else `false`. - * @api public - */ - -MapCache.prototype.has = function mapHas(key) { - return key !== '__proto__' && hasOwn.call(this.__data__, key); -}; - -/** - * Removes `key` and its value from the cache. - * - * ```js - * cache.del('foo'); - * ``` - * @title .del - * @param {String} `key` The key of the value to remove. - * @returns {Boolean} Returns `true` if the entry was removed successfully, else `false`. - * @api public - */ - -MapCache.prototype.del = function mapDelete(key) { - return this.has(key) && delete this.__data__[key]; -}; - - -/***/ }), -/* 829 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var define = __webpack_require__(730); - -/** - * Store position for a node - */ - -module.exports = function Position(start, parser) { - this.start = start; - this.end = { line: parser.line, column: parser.column }; - define(this, 'content', parser.orig); - define(this, 'source', parser.options.source); -}; - - -/***/ }), -/* 830 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var safe = __webpack_require__(831); -var define = __webpack_require__(837); -var extend = __webpack_require__(838); -var not = __webpack_require__(840); -var MAX_LENGTH = 1024 * 64; - -/** - * Session cache - */ - -var cache = {}; - -/** - * Create a regular expression from the given `pattern` string. - * - * @param {String|RegExp} `pattern` Pattern can be a string or regular expression. - * @param {Object} `options` - * @return {RegExp} - * @api public - */ - -module.exports = function(patterns, options) { - if (!Array.isArray(patterns)) { - return makeRe(patterns, options); - } - return makeRe(patterns.join('|'), options); -}; - -/** - * Create a regular expression from the given `pattern` string. - * - * @param {String|RegExp} `pattern` Pattern can be a string or regular expression. - * @param {Object} `options` - * @return {RegExp} - * @api public - */ - -function makeRe(pattern, options) { - if (pattern instanceof RegExp) { - return pattern; - } - - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - if (pattern.length > MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); - } - - var key = pattern; - // do this before shallow cloning options, it's a lot faster - if (!options || (options && options.cache !== false)) { - key = createKey(pattern, options); - - if (cache.hasOwnProperty(key)) { - return cache[key]; - } - } - - var opts = extend({}, options); - if (opts.contains === true) { - if (opts.negate === true) { - opts.strictNegate = false; - } else { - opts.strict = false; - } - } - - if (opts.strict === false) { - opts.strictOpen = false; - opts.strictClose = false; - } - - var open = opts.strictOpen !== false ? '^' : ''; - var close = opts.strictClose !== false ? '$' : ''; - var flags = opts.flags || ''; - var regex; - - if (opts.nocase === true && !/i/.test(flags)) { - flags += 'i'; - } - - try { - if (opts.negate || typeof opts.strictNegate === 'boolean') { - pattern = not.create(pattern, opts); - } - - var str = open + '(?:' + pattern + ')' + close; - regex = new RegExp(str, flags); - - if (opts.safe === true && safe(regex) === false) { - throw new Error('potentially unsafe regular expression: ' + regex.source); - } - - } catch (err) { - if (opts.strictErrors === true || opts.safe === true) { - err.key = key; - err.pattern = pattern; - err.originalOptions = options; - err.createdOptions = opts; - throw err; - } - - try { - regex = new RegExp('^' + pattern.replace(/(\W)/g, '\\$1') + '$'); - } catch (err) { - regex = /.^/; //<= match nothing - } - } - - if (opts.cache !== false) { - memoize(regex, key, pattern, opts); - } - return regex; -} - -/** - * Memoize generated regex. This can result in dramatic speed improvements - * and simplify debugging by adding options and pattern to the regex. It can be - * disabled by passing setting `options.cache` to false. - */ - -function memoize(regex, key, pattern, options) { - define(regex, 'cached', true); - define(regex, 'pattern', pattern); - define(regex, 'options', options); - define(regex, 'key', key); - cache[key] = regex; -} - -/** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ - -function createKey(pattern, options) { - if (!options) return pattern; - var key = pattern; - for (var prop in options) { - if (options.hasOwnProperty(prop)) { - key += ';' + prop + '=' + String(options[prop]); - } - } - return key; -} - -/** - * Expose `makeRe` - */ - -module.exports.makeRe = makeRe; - - -/***/ }), -/* 831 */ -/***/ (function(module, exports, __webpack_require__) { - -var parse = __webpack_require__(832); -var types = parse.types; - -module.exports = function (re, opts) { - if (!opts) opts = {}; - var replimit = opts.limit === undefined ? 25 : opts.limit; - - if (isRegExp(re)) re = re.source; - else if (typeof re !== 'string') re = String(re); - - try { re = parse(re) } - catch (err) { return false } - - var reps = 0; - return (function walk (node, starHeight) { - if (node.type === types.REPETITION) { - starHeight ++; - reps ++; - if (starHeight > 1) return false; - if (reps > replimit) return false; - } - - if (node.options) { - for (var i = 0, len = node.options.length; i < len; i++) { - var ok = walk({ stack: node.options[i] }, starHeight); - if (!ok) return false; - } - } - var stack = node.stack || (node.value && node.value.stack); - if (!stack) return true; - - for (var i = 0; i < stack.length; i++) { - var ok = walk(stack[i], starHeight); - if (!ok) return false; - } - - return true; - })(re, 0); -}; - -function isRegExp (x) { - return {}.toString.call(x) === '[object RegExp]'; -} - - -/***/ }), -/* 832 */ -/***/ (function(module, exports, __webpack_require__) { - -var util = __webpack_require__(833); -var types = __webpack_require__(834); -var sets = __webpack_require__(835); -var positions = __webpack_require__(836); - - -module.exports = function(regexpStr) { - var i = 0, l, c, - start = { type: types.ROOT, stack: []}, - - // Keep track of last clause/group and stack. - lastGroup = start, - last = start.stack, - groupStack = []; - - - var repeatErr = function(i) { - util.error(regexpStr, 'Nothing to repeat at column ' + (i - 1)); - }; - - // Decode a few escaped characters. - var str = util.strToChars(regexpStr); - l = str.length; - - // Iterate through each character in string. - while (i < l) { - c = str[i++]; - - switch (c) { - // Handle escaped characters, inclues a few sets. - case '\\': - c = str[i++]; - - switch (c) { - case 'b': - last.push(positions.wordBoundary()); - break; - - case 'B': - last.push(positions.nonWordBoundary()); - break; - - case 'w': - last.push(sets.words()); - break; - - case 'W': - last.push(sets.notWords()); - break; - - case 'd': - last.push(sets.ints()); - break; - - case 'D': - last.push(sets.notInts()); - break; - - case 's': - last.push(sets.whitespace()); - break; - - case 'S': - last.push(sets.notWhitespace()); - break; - - default: - // Check if c is integer. - // In which case it's a reference. - if (/\d/.test(c)) { - last.push({ type: types.REFERENCE, value: parseInt(c, 10) }); - - // Escaped character. - } else { - last.push({ type: types.CHAR, value: c.charCodeAt(0) }); - } - } - - break; - - - // Positionals. - case '^': - last.push(positions.begin()); - break; - - case '$': - last.push(positions.end()); - break; - - - // Handle custom sets. - case '[': - // Check if this class is 'anti' i.e. [^abc]. - var not; - if (str[i] === '^') { - not = true; - i++; - } else { - not = false; - } - - // Get all the characters in class. - var classTokens = util.tokenizeClass(str.slice(i), regexpStr); - - // Increase index by length of class. - i += classTokens[1]; - last.push({ - type: types.SET, - set: classTokens[0], - not: not, - }); - - break; - - - // Class of any character except \n. - case '.': - last.push(sets.anyChar()); - break; - - - // Push group onto stack. - case '(': - // Create group. - var group = { - type: types.GROUP, - stack: [], - remember: true, - }; - - c = str[i]; - - // If if this is a special kind of group. - if (c === '?') { - c = str[i + 1]; - i += 2; - - // Match if followed by. - if (c === '=') { - group.followedBy = true; - - // Match if not followed by. - } else if (c === '!') { - group.notFollowedBy = true; - - } else if (c !== ':') { - util.error(regexpStr, - 'Invalid group, character \'' + c + - '\' after \'?\' at column ' + (i - 1)); - } - - group.remember = false; - } - - // Insert subgroup into current group stack. - last.push(group); - - // Remember the current group for when the group closes. - groupStack.push(lastGroup); - - // Make this new group the current group. - lastGroup = group; - last = group.stack; - break; - - - // Pop group out of stack. - case ')': - if (groupStack.length === 0) { - util.error(regexpStr, 'Unmatched ) at column ' + (i - 1)); - } - lastGroup = groupStack.pop(); - - // Check if this group has a PIPE. - // To get back the correct last stack. - last = lastGroup.options ? - lastGroup.options[lastGroup.options.length - 1] : lastGroup.stack; - break; - - - // Use pipe character to give more choices. - case '|': - // Create array where options are if this is the first PIPE - // in this clause. - if (!lastGroup.options) { - lastGroup.options = [lastGroup.stack]; - delete lastGroup.stack; - } - - // Create a new stack and add to options for rest of clause. - var stack = []; - lastGroup.options.push(stack); - last = stack; - break; - - - // Repetition. - // For every repetition, remove last element from last stack - // then insert back a RANGE object. - // This design is chosen because there could be more than - // one repetition symbols in a regex i.e. `a?+{2,3}`. - case '{': - var rs = /^(\d+)(,(\d+)?)?\}/.exec(str.slice(i)), min, max; - if (rs !== null) { - if (last.length === 0) { - repeatErr(i); - } - min = parseInt(rs[1], 10); - max = rs[2] ? rs[3] ? parseInt(rs[3], 10) : Infinity : min; - i += rs[0].length; - - last.push({ - type: types.REPETITION, - min: min, - max: max, - value: last.pop(), - }); - } else { - last.push({ - type: types.CHAR, - value: 123, - }); - } - break; - - case '?': - if (last.length === 0) { - repeatErr(i); - } - last.push({ - type: types.REPETITION, - min: 0, - max: 1, - value: last.pop(), - }); - break; - - case '+': - if (last.length === 0) { - repeatErr(i); - } - last.push({ - type: types.REPETITION, - min: 1, - max: Infinity, - value: last.pop(), - }); - break; - - case '*': - if (last.length === 0) { - repeatErr(i); - } - last.push({ - type: types.REPETITION, - min: 0, - max: Infinity, - value: last.pop(), - }); - break; - - - // Default is a character that is not `\[](){}?+*^$`. - default: - last.push({ - type: types.CHAR, - value: c.charCodeAt(0), - }); - } - - } - - // Check if any groups have not been closed. - if (groupStack.length !== 0) { - util.error(regexpStr, 'Unterminated group'); - } - - return start; -}; - -module.exports.types = types; - - -/***/ }), -/* 833 */ -/***/ (function(module, exports, __webpack_require__) { - -var types = __webpack_require__(834); -var sets = __webpack_require__(835); - - -// All of these are private and only used by randexp. -// It's assumed that they will always be called with the correct input. - -var CTRL = '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ ?'; -var SLSH = { '0': 0, 't': 9, 'n': 10, 'v': 11, 'f': 12, 'r': 13 }; - -/** - * Finds character representations in str and convert all to - * their respective characters - * - * @param {String} str - * @return {String} - */ -exports.strToChars = function(str) { - /* jshint maxlen: false */ - var chars_regex = /(\[\\b\])|(\\)?\\(?:u([A-F0-9]{4})|x([A-F0-9]{2})|(0?[0-7]{2})|c([@A-Z\[\\\]\^?])|([0tnvfr]))/g; - str = str.replace(chars_regex, function(s, b, lbs, a16, b16, c8, dctrl, eslsh) { - if (lbs) { - return s; - } - - var code = b ? 8 : - a16 ? parseInt(a16, 16) : - b16 ? parseInt(b16, 16) : - c8 ? parseInt(c8, 8) : - dctrl ? CTRL.indexOf(dctrl) : - SLSH[eslsh]; - - var c = String.fromCharCode(code); - - // Escape special regex characters. - if (/[\[\]{}\^$.|?*+()]/.test(c)) { - c = '\\' + c; - } - - return c; - }); - - return str; -}; - - -/** - * turns class into tokens - * reads str until it encounters a ] not preceeded by a \ - * - * @param {String} str - * @param {String} regexpStr - * @return {Array., Number>} - */ -exports.tokenizeClass = function(str, regexpStr) { - /* jshint maxlen: false */ - var tokens = []; - var regexp = /\\(?:(w)|(d)|(s)|(W)|(D)|(S))|((?:(?:\\)(.)|([^\]\\]))-(?:\\)?([^\]]))|(\])|(?:\\)?(.)/g; - var rs, c; - - - while ((rs = regexp.exec(str)) != null) { - if (rs[1]) { - tokens.push(sets.words()); - - } else if (rs[2]) { - tokens.push(sets.ints()); - - } else if (rs[3]) { - tokens.push(sets.whitespace()); - - } else if (rs[4]) { - tokens.push(sets.notWords()); - - } else if (rs[5]) { - tokens.push(sets.notInts()); - - } else if (rs[6]) { - tokens.push(sets.notWhitespace()); - - } else if (rs[7]) { - tokens.push({ - type: types.RANGE, - from: (rs[8] || rs[9]).charCodeAt(0), - to: rs[10].charCodeAt(0), - }); - - } else if (c = rs[12]) { - tokens.push({ - type: types.CHAR, - value: c.charCodeAt(0), - }); - - } else { - return [tokens, regexp.lastIndex]; - } - } - - exports.error(regexpStr, 'Unterminated character class'); -}; - - -/** - * Shortcut to throw errors. - * - * @param {String} regexp - * @param {String} msg - */ -exports.error = function(regexp, msg) { - throw new SyntaxError('Invalid regular expression: /' + regexp + '/: ' + msg); -}; - - -/***/ }), -/* 834 */ -/***/ (function(module, exports) { - -module.exports = { - ROOT : 0, - GROUP : 1, - POSITION : 2, - SET : 3, - RANGE : 4, - REPETITION : 5, - REFERENCE : 6, - CHAR : 7, -}; - - -/***/ }), -/* 835 */ -/***/ (function(module, exports, __webpack_require__) { - -var types = __webpack_require__(834); - -var INTS = function() { - return [{ type: types.RANGE , from: 48, to: 57 }]; -}; - -var WORDS = function() { - return [ - { type: types.CHAR, value: 95 }, - { type: types.RANGE, from: 97, to: 122 }, - { type: types.RANGE, from: 65, to: 90 } - ].concat(INTS()); -}; - -var WHITESPACE = function() { - return [ - { type: types.CHAR, value: 9 }, - { type: types.CHAR, value: 10 }, - { type: types.CHAR, value: 11 }, - { type: types.CHAR, value: 12 }, - { type: types.CHAR, value: 13 }, - { type: types.CHAR, value: 32 }, - { type: types.CHAR, value: 160 }, - { type: types.CHAR, value: 5760 }, - { type: types.CHAR, value: 6158 }, - { type: types.CHAR, value: 8192 }, - { type: types.CHAR, value: 8193 }, - { type: types.CHAR, value: 8194 }, - { type: types.CHAR, value: 8195 }, - { type: types.CHAR, value: 8196 }, - { type: types.CHAR, value: 8197 }, - { type: types.CHAR, value: 8198 }, - { type: types.CHAR, value: 8199 }, - { type: types.CHAR, value: 8200 }, - { type: types.CHAR, value: 8201 }, - { type: types.CHAR, value: 8202 }, - { type: types.CHAR, value: 8232 }, - { type: types.CHAR, value: 8233 }, - { type: types.CHAR, value: 8239 }, - { type: types.CHAR, value: 8287 }, - { type: types.CHAR, value: 12288 }, - { type: types.CHAR, value: 65279 } - ]; -}; - -var NOTANYCHAR = function() { - return [ - { type: types.CHAR, value: 10 }, - { type: types.CHAR, value: 13 }, - { type: types.CHAR, value: 8232 }, - { type: types.CHAR, value: 8233 }, - ]; -}; - -// Predefined class objects. -exports.words = function() { - return { type: types.SET, set: WORDS(), not: false }; -}; - -exports.notWords = function() { - return { type: types.SET, set: WORDS(), not: true }; -}; - -exports.ints = function() { - return { type: types.SET, set: INTS(), not: false }; -}; - -exports.notInts = function() { - return { type: types.SET, set: INTS(), not: true }; -}; - -exports.whitespace = function() { - return { type: types.SET, set: WHITESPACE(), not: false }; -}; - -exports.notWhitespace = function() { - return { type: types.SET, set: WHITESPACE(), not: true }; -}; - -exports.anyChar = function() { - return { type: types.SET, set: NOTANYCHAR(), not: true }; -}; - - -/***/ }), -/* 836 */ -/***/ (function(module, exports, __webpack_require__) { - -var types = __webpack_require__(834); - -exports.wordBoundary = function() { - return { type: types.POSITION, value: 'b' }; -}; - -exports.nonWordBoundary = function() { - return { type: types.POSITION, value: 'B' }; -}; - -exports.begin = function() { - return { type: types.POSITION, value: '^' }; -}; - -exports.end = function() { - return { type: types.POSITION, value: '$' }; -}; - - -/***/ }), -/* 837 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015-2018, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isobject = __webpack_require__(748); -var isDescriptor = __webpack_require__(760); -var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) - ? Reflect.defineProperty - : Object.defineProperty; - -module.exports = function defineProperty(obj, key, val) { - if (!isobject(obj) && typeof obj !== 'function' && !Array.isArray(obj)) { - throw new TypeError('expected an object, function, or array'); - } - - if (typeof key !== 'string') { - throw new TypeError('expected "key" to be a string'); - } - - if (isDescriptor(val)) { - define(obj, key, val); - return obj; - } - - define(obj, key, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); - - return obj; -}; - - -/***/ }), -/* 838 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isExtendable = __webpack_require__(839); -var assignSymbols = __webpack_require__(749); - -module.exports = Object.assign || function(obj/*, objects*/) { - if (obj === null || typeof obj === 'undefined') { - throw new TypeError('Cannot convert undefined or null to object'); - } - if (!isObject(obj)) { - obj = {}; - } - for (var i = 1; i < arguments.length; i++) { - var val = arguments[i]; - if (isString(val)) { - val = toObject(val); - } - if (isObject(val)) { - assign(obj, val); - assignSymbols(obj, val); - } - } - return obj; -}; - -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } - } -} - -function isString(val) { - return (val && typeof val === 'string'); -} - -function toObject(str) { - var obj = {}; - for (var i in str) { - obj[i] = str[i]; - } - return obj; -} - -function isObject(val) { - return (val && typeof val === 'object') || isExtendable(val); -} - -/** - * Returns true if the given `key` is an own property of `obj`. - */ - -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - -function isEnum(obj, key) { - return Object.prototype.propertyIsEnumerable.call(obj, key); -} - - -/***/ }), -/* 839 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isPlainObject = __webpack_require__(747); - -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); -}; - - -/***/ }), -/* 840 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var extend = __webpack_require__(838); -var safe = __webpack_require__(831); - -/** - * The main export is a function that takes a `pattern` string and an `options` object. - * - * ```js - & var not = require('regex-not'); - & console.log(not('foo')); - & //=> /^(?:(?!^(?:foo)$).)*$/ - * ``` - * - * @param {String} `pattern` - * @param {Object} `options` - * @return {RegExp} Converts the given `pattern` to a regex using the specified `options`. - * @api public - */ - -function toRegex(pattern, options) { - return new RegExp(toRegex.create(pattern, options)); -} - -/** - * Create a regex-compatible string from the given `pattern` and `options`. - * - * ```js - & var not = require('regex-not'); - & console.log(not.create('foo')); - & //=> '^(?:(?!^(?:foo)$).)*$' - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {String} - * @api public - */ - -toRegex.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - var opts = extend({}, options); - if (opts.contains === true) { - opts.strictNegate = false; - } - - var open = opts.strictOpen !== false ? '^' : ''; - var close = opts.strictClose !== false ? '$' : ''; - var endChar = opts.endChar ? opts.endChar : '+'; - var str = pattern; - - if (opts.strictNegate === false) { - str = '(?:(?!(?:' + pattern + ')).)' + endChar; - } else { - str = '(?:(?!^(?:' + pattern + ')$).)' + endChar; - } - - var res = open + str + close; - if (opts.safe === true && safe(res) === false) { - throw new Error('potentially unsafe regular expression: ' + res); - } - - return res; -}; - -/** - * Expose `toRegex` - */ - -module.exports = toRegex; - - -/***/ }), -/* 841 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var nanomatch = __webpack_require__(842); -var extglob = __webpack_require__(857); - -module.exports = function(snapdragon) { - var compilers = snapdragon.compiler.compilers; - var opts = snapdragon.options; - - // register nanomatch compilers - snapdragon.use(nanomatch.compilers); - - // get references to some specific nanomatch compilers before they - // are overridden by the extglob and/or custom compilers - var escape = compilers.escape; - var qmark = compilers.qmark; - var slash = compilers.slash; - var star = compilers.star; - var text = compilers.text; - var plus = compilers.plus; - var dot = compilers.dot; - - // register extglob compilers or escape exglobs if disabled - if (opts.extglob === false || opts.noext === true) { - snapdragon.compiler.use(escapeExtglobs); - } else { - snapdragon.use(extglob.compilers); - } - - snapdragon.use(function() { - this.options.star = this.options.star || function(/*node*/) { - return '[^\\\\/]*?'; - }; - }); - - // custom micromatch compilers - snapdragon.compiler - - // reset referenced compiler - .set('dot', dot) - .set('escape', escape) - .set('plus', plus) - .set('slash', slash) - .set('qmark', qmark) - .set('star', star) - .set('text', text); -}; - -function escapeExtglobs(compiler) { - compiler.set('paren', function(node) { - var val = ''; - visit(node, function(tok) { - if (tok.val) val += (/^\W/.test(tok.val) ? '\\' : '') + tok.val; - }); - return this.emit(val, node); - }); - - /** - * Visit `node` with the given `fn` - */ - - function visit(node, fn) { - return node.nodes ? mapVisit(node.nodes, fn) : fn(node); - } - - /** - * Map visit over array of `nodes`. - */ - - function mapVisit(nodes, fn) { - var len = nodes.length; - var idx = -1; - while (++idx < len) { - visit(nodes[idx], fn); - } - } -} - - -/***/ }), -/* 842 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Module dependencies - */ - -var util = __webpack_require__(29); -var toRegex = __webpack_require__(729); -var extend = __webpack_require__(843); - -/** - * Local dependencies - */ - -var compilers = __webpack_require__(845); -var parsers = __webpack_require__(846); -var cache = __webpack_require__(849); -var utils = __webpack_require__(851); -var MAX_LENGTH = 1024 * 64; - -/** - * The main function takes a list of strings and one or more - * glob patterns to use for matching. - * - * ```js - * var nm = require('nanomatch'); - * nm(list, patterns[, options]); - * - * console.log(nm(['a.js', 'a.txt'], ['*.js'])); - * //=> [ 'a.js' ] - * ``` - * @param {Array} `list` A list of strings to match - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of matches - * @summary false - * @api public - */ - -function nanomatch(list, patterns, options) { - patterns = utils.arrayify(patterns); - list = utils.arrayify(list); - - var len = patterns.length; - if (list.length === 0 || len === 0) { - return []; - } - - if (len === 1) { - return nanomatch.match(list, patterns[0], options); - } - - var negated = false; - var omit = []; - var keep = []; - var idx = -1; - - while (++idx < len) { - var pattern = patterns[idx]; - - if (typeof pattern === 'string' && pattern.charCodeAt(0) === 33 /* ! */) { - omit.push.apply(omit, nanomatch.match(list, pattern.slice(1), options)); - negated = true; - } else { - keep.push.apply(keep, nanomatch.match(list, pattern, options)); - } - } - - // minimatch.match parity - if (negated && keep.length === 0) { - if (options && options.unixify === false) { - keep = list.slice(); - } else { - var unixify = utils.unixify(options); - for (var i = 0; i < list.length; i++) { - keep.push(unixify(list[i])); - } - } - } - - var matches = utils.diff(keep, omit); - if (!options || options.nodupes !== false) { - return utils.unique(matches); - } - - return matches; -} - -/** - * Similar to the main function, but `pattern` must be a string. - * - * ```js - * var nm = require('nanomatch'); - * nm.match(list, pattern[, options]); - * - * console.log(nm.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); - * //=> ['a.a', 'a.aa'] - * ``` - * @param {Array} `list` Array of strings to match - * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of matches - * @api public - */ - -nanomatch.match = function(list, pattern, options) { - if (Array.isArray(pattern)) { - throw new TypeError('expected pattern to be a string'); - } - - var unixify = utils.unixify(options); - var isMatch = memoize('match', pattern, options, nanomatch.matcher); - var matches = []; - - list = utils.arrayify(list); - var len = list.length; - var idx = -1; - - while (++idx < len) { - var ele = list[idx]; - if (ele === pattern || isMatch(ele)) { - matches.push(utils.value(ele, unixify, options)); - } - } - - // if no options were passed, uniquify results and return - if (typeof options === 'undefined') { - return utils.unique(matches); - } - - if (matches.length === 0) { - if (options.failglob === true) { - throw new Error('no matches found for "' + pattern + '"'); - } - if (options.nonull === true || options.nullglob === true) { - return [options.unescape ? utils.unescape(pattern) : pattern]; - } - } - - // if `opts.ignore` was defined, diff ignored list - if (options.ignore) { - matches = nanomatch.not(matches, options.ignore, options); - } - - return options.nodupes !== false ? utils.unique(matches) : matches; -}; - -/** - * Returns true if the specified `string` matches the given glob `pattern`. - * - * ```js - * var nm = require('nanomatch'); - * nm.isMatch(string, pattern[, options]); - * - * console.log(nm.isMatch('a.a', '*.a')); - * //=> true - * console.log(nm.isMatch('a.b', '*.a')); - * //=> false - * ``` - * @param {String} `string` String to match - * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if the string matches the glob pattern. - * @api public - */ - -nanomatch.isMatch = function(str, pattern, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (utils.isEmptyString(str) || utils.isEmptyString(pattern)) { - return false; - } - - var equals = utils.equalsPattern(options); - if (equals(str)) { - return true; - } - - var isMatch = memoize('isMatch', pattern, options, nanomatch.matcher); - return isMatch(str); -}; - -/** - * Returns true if some of the elements in the given `list` match any of the - * given glob `patterns`. - * - * ```js - * var nm = require('nanomatch'); - * nm.some(list, patterns[, options]); - * - * console.log(nm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); - * // true - * console.log(nm.some(['foo.js'], ['*.js', '!foo.js'])); - * // false - * ``` - * @param {String|Array} `list` The string or array of strings to test. Returns as soon as the first match is found. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -nanomatch.some = function(list, patterns, options) { - if (typeof list === 'string') { - list = [list]; - } - - for (var i = 0; i < list.length; i++) { - if (nanomatch(list[i], patterns, options).length === 1) { - return true; - } - } - - return false; -}; - -/** - * Returns true if every element in the given `list` matches - * at least one of the given glob `patterns`. - * - * ```js - * var nm = require('nanomatch'); - * nm.every(list, patterns[, options]); - * - * console.log(nm.every('foo.js', ['foo.js'])); - * // true - * console.log(nm.every(['foo.js', 'bar.js'], ['*.js'])); - * // true - * console.log(nm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); - * // false - * console.log(nm.every(['foo.js'], ['*.js', '!foo.js'])); - * // false - * ``` - * @param {String|Array} `list` The string or array of strings to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -nanomatch.every = function(list, patterns, options) { - if (typeof list === 'string') { - list = [list]; - } - - for (var i = 0; i < list.length; i++) { - if (nanomatch(list[i], patterns, options).length !== 1) { - return false; - } - } - - return true; -}; - -/** - * Returns true if **any** of the given glob `patterns` - * match the specified `string`. - * - * ```js - * var nm = require('nanomatch'); - * nm.any(string, patterns[, options]); - * - * console.log(nm.any('a.a', ['b.*', '*.a'])); - * //=> true - * console.log(nm.any('a.a', 'b.*')); - * //=> false - * ``` - * @param {String|Array} `str` The string to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -nanomatch.any = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (utils.isEmptyString(str) || utils.isEmptyString(patterns)) { - return false; - } - - if (typeof patterns === 'string') { - patterns = [patterns]; - } - - for (var i = 0; i < patterns.length; i++) { - if (nanomatch.isMatch(str, patterns[i], options)) { - return true; - } - } - return false; -}; - -/** - * Returns true if **all** of the given `patterns` - * match the specified string. - * - * ```js - * var nm = require('nanomatch'); - * nm.all(string, patterns[, options]); - * - * console.log(nm.all('foo.js', ['foo.js'])); - * // true - * - * console.log(nm.all('foo.js', ['*.js', '!foo.js'])); - * // false - * - * console.log(nm.all('foo.js', ['*.js', 'foo.js'])); - * // true - * - * console.log(nm.all('foo.js', ['*.js', 'f*', '*o*', '*o.js'])); - * // true - * ``` - * @param {String|Array} `str` The string to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -nanomatch.all = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (typeof patterns === 'string') { - patterns = [patterns]; - } - - for (var i = 0; i < patterns.length; i++) { - if (!nanomatch.isMatch(str, patterns[i], options)) { - return false; - } - } - return true; -}; - -/** - * Returns a list of strings that _**do not match any**_ of the given `patterns`. - * - * ```js - * var nm = require('nanomatch'); - * nm.not(list, patterns[, options]); - * - * console.log(nm.not(['a.a', 'b.b', 'c.c'], '*.a')); - * //=> ['b.b', 'c.c'] - * ``` - * @param {Array} `list` Array of strings to match. - * @param {String|Array} `patterns` One or more glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of strings that **do not match** the given patterns. - * @api public - */ - -nanomatch.not = function(list, patterns, options) { - var opts = extend({}, options); - var ignore = opts.ignore; - delete opts.ignore; - - list = utils.arrayify(list); - - var matches = utils.diff(list, nanomatch(list, patterns, opts)); - if (ignore) { - matches = utils.diff(matches, nanomatch(list, ignore)); - } - - return opts.nodupes !== false ? utils.unique(matches) : matches; -}; - -/** - * Returns true if the given `string` contains the given pattern. Similar - * to [.isMatch](#isMatch) but the pattern can match any part of the string. - * - * ```js - * var nm = require('nanomatch'); - * nm.contains(string, pattern[, options]); - * - * console.log(nm.contains('aa/bb/cc', '*b')); - * //=> true - * console.log(nm.contains('aa/bb/cc', '*d')); - * //=> false - * ``` - * @param {String} `str` The string to match. - * @param {String|Array} `patterns` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if the patter matches any part of `str`. - * @api public - */ - -nanomatch.contains = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (typeof patterns === 'string') { - if (utils.isEmptyString(str) || utils.isEmptyString(patterns)) { - return false; - } - - var equals = utils.equalsPattern(patterns, options); - if (equals(str)) { - return true; - } - var contains = utils.containsPattern(patterns, options); - if (contains(str)) { - return true; - } - } - - var opts = extend({}, options, {contains: true}); - return nanomatch.any(str, patterns, opts); -}; - -/** - * Returns true if the given pattern and options should enable - * the `matchBase` option. - * @return {Boolean} - * @api private - */ - -nanomatch.matchBase = function(pattern, options) { - if (pattern && pattern.indexOf('/') !== -1 || !options) return false; - return options.basename === true || options.matchBase === true; -}; - -/** - * Filter the keys of the given object with the given `glob` pattern - * and `options`. Does not attempt to match nested keys. If you need this feature, - * use [glob-object][] instead. - * - * ```js - * var nm = require('nanomatch'); - * nm.matchKeys(object, patterns[, options]); - * - * var obj = { aa: 'a', ab: 'b', ac: 'c' }; - * console.log(nm.matchKeys(obj, '*b')); - * //=> { ab: 'b' } - * ``` - * @param {Object} `object` The object with keys to filter. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Object} Returns an object with only keys that match the given patterns. - * @api public - */ - -nanomatch.matchKeys = function(obj, patterns, options) { - if (!utils.isObject(obj)) { - throw new TypeError('expected the first argument to be an object'); - } - var keys = nanomatch(Object.keys(obj), patterns, options); - return utils.pick(obj, keys); -}; - -/** - * Returns a memoized matcher function from the given glob `pattern` and `options`. - * The returned function takes a string to match as its only argument and returns - * true if the string is a match. - * - * ```js - * var nm = require('nanomatch'); - * nm.matcher(pattern[, options]); - * - * var isMatch = nm.matcher('*.!(*a)'); - * console.log(isMatch('a.a')); - * //=> false - * console.log(isMatch('a.b')); - * //=> true - * ``` - * @param {String} `pattern` Glob pattern - * @param {Object} `options` See available [options](#options) for changing how matches are performed. - * @return {Function} Returns a matcher function. - * @api public - */ - -nanomatch.matcher = function matcher(pattern, options) { - if (utils.isEmptyString(pattern)) { - return function() { - return false; - }; - } - - if (Array.isArray(pattern)) { - return compose(pattern, options, matcher); - } - - // if pattern is a regex - if (pattern instanceof RegExp) { - return test(pattern); - } - - // if pattern is invalid - if (!utils.isString(pattern)) { - throw new TypeError('expected pattern to be an array, string or regex'); - } - - // if pattern is a non-glob string - if (!utils.hasSpecialChars(pattern)) { - if (options && options.nocase === true) { - pattern = pattern.toLowerCase(); - } - return utils.matchPath(pattern, options); - } - - // if pattern is a glob string - var re = nanomatch.makeRe(pattern, options); - - // if `options.matchBase` or `options.basename` is defined - if (nanomatch.matchBase(pattern, options)) { - return utils.matchBasename(re, options); - } - - function test(regex) { - var equals = utils.equalsPattern(options); - var unixify = utils.unixify(options); - - return function(str) { - if (equals(str)) { - return true; - } - - if (regex.test(unixify(str))) { - return true; - } - return false; - }; - } - - // create matcher function - var matcherFn = test(re); - // set result object from compiler on matcher function, - // as a non-enumerable property. useful for debugging - utils.define(matcherFn, 'result', re.result); - return matcherFn; -}; - -/** - * Returns an array of matches captured by `pattern` in `string, or - * `null` if the pattern did not match. - * - * ```js - * var nm = require('nanomatch'); - * nm.capture(pattern, string[, options]); - * - * console.log(nm.capture('test/*.js', 'test/foo.js')); - * //=> ['foo'] - * console.log(nm.capture('test/*.js', 'foo/bar.css')); - * //=> null - * ``` - * @param {String} `pattern` Glob pattern to use for matching. - * @param {String} `string` String to match - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns an array of captures if the string matches the glob pattern, otherwise `null`. - * @api public - */ - -nanomatch.capture = function(pattern, str, options) { - var re = nanomatch.makeRe(pattern, extend({capture: true}, options)); - var unixify = utils.unixify(options); - - function match() { - return function(string) { - var match = re.exec(unixify(string)); - if (!match) { - return null; - } - - return match.slice(1); - }; - } - - var capture = memoize('capture', pattern, options, match); - return capture(str); -}; - -/** - * Create a regular expression from the given glob `pattern`. - * - * ```js - * var nm = require('nanomatch'); - * nm.makeRe(pattern[, options]); - * - * console.log(nm.makeRe('*.js')); - * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ - * ``` - * @param {String} `pattern` A glob pattern to convert to regex. - * @param {Object} `options` See available [options](#options) for changing how matches are performed. - * @return {RegExp} Returns a regex created from the given pattern. - * @api public - */ - -nanomatch.makeRe = function(pattern, options) { - if (pattern instanceof RegExp) { - return pattern; - } - - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - if (pattern.length > MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); - } - - function makeRe() { - var opts = utils.extend({wrap: false}, options); - var result = nanomatch.create(pattern, opts); - var regex = toRegex(result.output, opts); - utils.define(regex, 'result', result); - return regex; - } - - return memoize('makeRe', pattern, options, makeRe); -}; - -/** - * Parses the given glob `pattern` and returns an object with the compiled `output` - * and optional source `map`. - * - * ```js - * var nm = require('nanomatch'); - * nm.create(pattern[, options]); - * - * console.log(nm.create('abc/*.js')); - * // { options: { source: 'string', sourcemap: true }, - * // state: {}, - * // compilers: - * // { ... }, - * // output: '(\\.[\\\\\\/])?abc\\/(?!\\.)(?=.)[^\\/]*?\\.js', - * // ast: - * // { type: 'root', - * // errors: [], - * // nodes: - * // [ ... ], - * // dot: false, - * // input: 'abc/*.js' }, - * // parsingErrors: [], - * // map: - * // { version: 3, - * // sources: [ 'string' ], - * // names: [], - * // mappings: 'AAAA,GAAG,EAAC,kBAAC,EAAC,EAAE', - * // sourcesContent: [ 'abc/*.js' ] }, - * // position: { line: 1, column: 28 }, - * // content: {}, - * // files: {}, - * // idx: 6 } - * ``` - * @param {String} `pattern` Glob pattern to parse and compile. - * @param {Object} `options` Any [options](#options) to change how parsing and compiling is performed. - * @return {Object} Returns an object with the parsed AST, compiled string and optional source map. - * @api public - */ - -nanomatch.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - function create() { - return nanomatch.compile(nanomatch.parse(pattern, options), options); - } - return memoize('create', pattern, options, create); -}; - -/** - * Parse the given `str` with the given `options`. - * - * ```js - * var nm = require('nanomatch'); - * nm.parse(pattern[, options]); - * - * var ast = nm.parse('a/{b,c}/d'); - * console.log(ast); - * // { type: 'root', - * // errors: [], - * // input: 'a/{b,c}/d', - * // nodes: - * // [ { type: 'bos', val: '' }, - * // { type: 'text', val: 'a/' }, - * // { type: 'brace', - * // nodes: - * // [ { type: 'brace.open', val: '{' }, - * // { type: 'text', val: 'b,c' }, - * // { type: 'brace.close', val: '}' } ] }, - * // { type: 'text', val: '/d' }, - * // { type: 'eos', val: '' } ] } - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {Object} Returns an AST - * @api public - */ - -nanomatch.parse = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - function parse() { - var snapdragon = utils.instantiate(null, options); - parsers(snapdragon, options); - - var ast = snapdragon.parse(pattern, options); - utils.define(ast, 'snapdragon', snapdragon); - ast.input = pattern; - return ast; - } - - return memoize('parse', pattern, options, parse); -}; - -/** - * Compile the given `ast` or string with the given `options`. - * - * ```js - * var nm = require('nanomatch'); - * nm.compile(ast[, options]); - * - * var ast = nm.parse('a/{b,c}/d'); - * console.log(nm.compile(ast)); - * // { options: { source: 'string' }, - * // state: {}, - * // compilers: - * // { eos: [Function], - * // noop: [Function], - * // bos: [Function], - * // brace: [Function], - * // 'brace.open': [Function], - * // text: [Function], - * // 'brace.close': [Function] }, - * // output: [ 'a/(b|c)/d' ], - * // ast: - * // { ... }, - * // parsingErrors: [] } - * ``` - * @param {Object|String} `ast` - * @param {Object} `options` - * @return {Object} Returns an object that has an `output` property with the compiled string. - * @api public - */ - -nanomatch.compile = function(ast, options) { - if (typeof ast === 'string') { - ast = nanomatch.parse(ast, options); - } - - function compile() { - var snapdragon = utils.instantiate(ast, options); - compilers(snapdragon, options); - return snapdragon.compile(ast, options); - } - - return memoize('compile', ast.input, options, compile); -}; - -/** - * Clear the regex cache. - * - * ```js - * nm.clearCache(); - * ``` - * @api public - */ - -nanomatch.clearCache = function() { - nanomatch.cache.__data__ = {}; -}; - -/** - * Compose a matcher function with the given patterns. - * This allows matcher functions to be compiled once and - * called multiple times. - */ - -function compose(patterns, options, matcher) { - var matchers; - - return memoize('compose', String(patterns), options, function() { - return function(file) { - // delay composition until it's invoked the first time, - // after that it won't be called again - if (!matchers) { - matchers = []; - for (var i = 0; i < patterns.length; i++) { - matchers.push(matcher(patterns[i], options)); - } - } - - var len = matchers.length; - while (len--) { - if (matchers[len](file) === true) { - return true; - } - } - return false; - }; - }); -} - -/** - * Memoize a generated regex or function. A unique key is generated - * from the `type` (usually method name), the `pattern`, and - * user-defined options. - */ - -function memoize(type, pattern, options, fn) { - var key = utils.createKey(type + '=' + pattern, options); - - if (options && options.cache === false) { - return fn(pattern, options); - } - - if (cache.has(type, key)) { - return cache.get(type, key); - } - - var val = fn(pattern, options); - cache.set(type, key, val); - return val; -} - -/** - * Expose compiler, parser and cache on `nanomatch` - */ - -nanomatch.compilers = compilers; -nanomatch.parsers = parsers; -nanomatch.cache = cache; - -/** - * Expose `nanomatch` - * @type {Function} - */ - -module.exports = nanomatch; - - -/***/ }), -/* 843 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isExtendable = __webpack_require__(844); -var assignSymbols = __webpack_require__(749); - -module.exports = Object.assign || function(obj/*, objects*/) { - if (obj === null || typeof obj === 'undefined') { - throw new TypeError('Cannot convert undefined or null to object'); - } - if (!isObject(obj)) { - obj = {}; - } - for (var i = 1; i < arguments.length; i++) { - var val = arguments[i]; - if (isString(val)) { - val = toObject(val); - } - if (isObject(val)) { - assign(obj, val); - assignSymbols(obj, val); - } - } - return obj; -}; - -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } - } -} - -function isString(val) { - return (val && typeof val === 'string'); -} - -function toObject(str) { - var obj = {}; - for (var i in str) { - obj[i] = str[i]; - } - return obj; -} - -function isObject(val) { - return (val && typeof val === 'object') || isExtendable(val); -} - -/** - * Returns true if the given `key` is an own property of `obj`. - */ - -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - -function isEnum(obj, key) { - return Object.prototype.propertyIsEnumerable.call(obj, key); -} - - -/***/ }), -/* 844 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isPlainObject = __webpack_require__(747); - -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); -}; - - -/***/ }), -/* 845 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** -* Nanomatch compilers -*/ - -module.exports = function(nanomatch, options) { - function slash() { - if (options && typeof options.slash === 'string') { - return options.slash; - } - if (options && typeof options.slash === 'function') { - return options.slash.call(nanomatch); - } - return '\\\\/'; - } - - function star() { - if (options && typeof options.star === 'string') { - return options.star; - } - if (options && typeof options.star === 'function') { - return options.star.call(nanomatch); - } - return '[^' + slash() + ']*?'; - } - - var ast = nanomatch.ast = nanomatch.parser.ast; - ast.state = nanomatch.parser.state; - nanomatch.compiler.state = ast.state; - nanomatch.compiler - - /** - * Negation / escaping - */ - - .set('not', function(node) { - var prev = this.prev(); - if (this.options.nonegate === true || prev.type !== 'bos') { - return this.emit('\\' + node.val, node); - } - return this.emit(node.val, node); - }) - .set('escape', function(node) { - if (this.options.unescape && /^[-\w_.]/.test(node.val)) { - return this.emit(node.val, node); - } - return this.emit('\\' + node.val, node); - }) - .set('quoted', function(node) { - return this.emit(node.val, node); - }) - - /** - * Regex - */ - - .set('dollar', function(node) { - if (node.parent.type === 'bracket') { - return this.emit(node.val, node); - } - return this.emit('\\' + node.val, node); - }) - - /** - * Dot: "." - */ - - .set('dot', function(node) { - if (node.dotfiles === true) this.dotfiles = true; - return this.emit('\\' + node.val, node); - }) - - /** - * Slashes: "/" and "\" - */ - - .set('backslash', function(node) { - return this.emit(node.val, node); - }) - .set('slash', function(node, nodes, i) { - var val = '[' + slash() + ']'; - var parent = node.parent; - var prev = this.prev(); - - // set "node.hasSlash" to true on all ancestor parens nodes - while (parent.type === 'paren' && !parent.hasSlash) { - parent.hasSlash = true; - parent = parent.parent; - } - - if (prev.addQmark) { - val += '?'; - } - - // word boundary - if (node.rest.slice(0, 2) === '\\b') { - return this.emit(val, node); - } - - // globstars - if (node.parsed === '**' || node.parsed === './**') { - this.output = '(?:' + this.output; - return this.emit(val + ')?', node); - } - - // negation - if (node.parsed === '!**' && this.options.nonegate !== true) { - return this.emit(val + '?\\b', node); - } - return this.emit(val, node); - }) - - /** - * Square brackets - */ - - .set('bracket', function(node) { - var close = node.close; - var open = !node.escaped ? '[' : '\\['; - var negated = node.negated; - var inner = node.inner; - var val = node.val; - - if (node.escaped === true) { - inner = inner.replace(/\\?(\W)/g, '\\$1'); - negated = ''; - } - - if (inner === ']-') { - inner = '\\]\\-'; - } - - if (negated && inner.indexOf('.') === -1) { - inner += '.'; - } - if (negated && inner.indexOf('/') === -1) { - inner += '/'; - } - - val = open + negated + inner + close; - return this.emit(val, node); - }) - - /** - * Square: "[.]" (only matches a single character in brackets) - */ - - .set('square', function(node) { - var val = (/^\W/.test(node.val) ? '\\' : '') + node.val; - return this.emit(val, node); - }) - - /** - * Question mark: "?" - */ - - .set('qmark', function(node) { - var prev = this.prev(); - // don't use "slash" variable so that we always avoid - // matching backslashes and slashes with a qmark - var val = '[^.\\\\/]'; - if (this.options.dot || (prev.type !== 'bos' && prev.type !== 'slash')) { - val = '[^\\\\/]'; - } - - if (node.parsed.slice(-1) === '(') { - var ch = node.rest.charAt(0); - if (ch === '!' || ch === '=' || ch === ':') { - return this.emit(node.val, node); - } - } - - if (node.val.length > 1) { - val += '{' + node.val.length + '}'; - } - return this.emit(val, node); - }) - - /** - * Plus - */ - - .set('plus', function(node) { - var prev = node.parsed.slice(-1); - if (prev === ']' || prev === ')') { - return this.emit(node.val, node); - } - if (!this.output || (/[?*+]/.test(ch) && node.parent.type !== 'bracket')) { - return this.emit('\\+', node); - } - var ch = this.output.slice(-1); - if (/\w/.test(ch) && !node.inside) { - return this.emit('+\\+?', node); - } - return this.emit('+', node); - }) - - /** - * globstar: '**' - */ - - .set('globstar', function(node, nodes, i) { - if (!this.output) { - this.state.leadingGlobstar = true; - } - - var prev = this.prev(); - var before = this.prev(2); - var next = this.next(); - var after = this.next(2); - var type = prev.type; - var val = node.val; - - if (prev.type === 'slash' && next.type === 'slash') { - if (before.type === 'text') { - this.output += '?'; - - if (after.type !== 'text') { - this.output += '\\b'; - } - } - } - - var parsed = node.parsed; - if (parsed.charAt(0) === '!') { - parsed = parsed.slice(1); - } - - var isInside = node.isInside.paren || node.isInside.brace; - if (parsed && type !== 'slash' && type !== 'bos' && !isInside) { - val = star(); - } else { - val = this.options.dot !== true - ? '(?:(?!(?:[' + slash() + ']|^)\\.).)*?' - : '(?:(?!(?:[' + slash() + ']|^)(?:\\.{1,2})($|[' + slash() + ']))(?!\\.{2}).)*?'; - } - - if ((type === 'slash' || type === 'bos') && this.options.dot !== true) { - val = '(?!\\.)' + val; - } - - if (prev.type === 'slash' && next.type === 'slash' && before.type !== 'text') { - if (after.type === 'text' || after.type === 'star') { - node.addQmark = true; - } - } - - if (this.options.capture) { - val = '(' + val + ')'; - } - - return this.emit(val, node); - }) - - /** - * Star: "*" - */ - - .set('star', function(node, nodes, i) { - var prior = nodes[i - 2] || {}; - var prev = this.prev(); - var next = this.next(); - var type = prev.type; - - function isStart(n) { - return n.type === 'bos' || n.type === 'slash'; - } - - if (this.output === '' && this.options.contains !== true) { - this.output = '(?![' + slash() + '])'; - } - - if (type === 'bracket' && this.options.bash === false) { - var str = next && next.type === 'bracket' ? star() : '*?'; - if (!prev.nodes || prev.nodes[1].type !== 'posix') { - return this.emit(str, node); - } - } - - var prefix = !this.dotfiles && type !== 'text' && type !== 'escape' - ? (this.options.dot ? '(?!(?:^|[' + slash() + '])\\.{1,2}(?:$|[' + slash() + ']))' : '(?!\\.)') - : ''; - - if (isStart(prev) || (isStart(prior) && type === 'not')) { - if (prefix !== '(?!\\.)') { - prefix += '(?!(\\.{2}|\\.[' + slash() + ']))(?=.)'; - } else { - prefix += '(?=.)'; - } - } else if (prefix === '(?!\\.)') { - prefix = ''; - } - - if (prev.type === 'not' && prior.type === 'bos' && this.options.dot === true) { - this.output = '(?!\\.)' + this.output; - } - - var output = prefix + star(); - if (this.options.capture) { - output = '(' + output + ')'; - } - - return this.emit(output, node); - }) - - /** - * Text - */ - - .set('text', function(node) { - return this.emit(node.val, node); - }) - - /** - * End-of-string - */ - - .set('eos', function(node) { - var prev = this.prev(); - var val = node.val; - - this.output = '(?:\\.[' + slash() + '](?=.))?' + this.output; - if (this.state.metachar && prev.type !== 'qmark' && prev.type !== 'slash') { - val += (this.options.contains ? '[' + slash() + ']?' : '(?:[' + slash() + ']|$)'); - } - - return this.emit(val, node); - }); - - /** - * Allow custom compilers to be passed on options - */ - - if (options && typeof options.compilers === 'function') { - options.compilers(nanomatch.compiler); - } -}; - - - -/***/ }), -/* 846 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var regexNot = __webpack_require__(740); -var toRegex = __webpack_require__(729); -var isOdd = __webpack_require__(847); - -/** - * Characters to use in negation regex (we want to "not" match - * characters that are matched by other parsers) - */ - -var cached; -var NOT_REGEX = '[\\[!*+?$^"\'.\\\\/]+'; -var not = createTextRegex(NOT_REGEX); - -/** - * Nanomatch parsers - */ - -module.exports = function(nanomatch, options) { - var parser = nanomatch.parser; - var opts = parser.options; - - parser.state = { - slashes: 0, - paths: [] - }; - - parser.ast.state = parser.state; - parser - - /** - * Beginning-of-string - */ - - .capture('prefix', function() { - if (this.parsed) return; - var m = this.match(/^\.[\\/]/); - if (!m) return; - this.state.strictOpen = !!this.options.strictOpen; - this.state.addPrefix = true; - }) - - /** - * Escape: "\\." - */ - - .capture('escape', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(/^(?:\\(.)|([$^]))/); - if (!m) return; - - return pos({ - type: 'escape', - val: m[2] || m[1] - }); - }) - - /** - * Quoted strings - */ - - .capture('quoted', function() { - var pos = this.position(); - var m = this.match(/^["']/); - if (!m) return; - - var quote = m[0]; - if (this.input.indexOf(quote) === -1) { - return pos({ - type: 'escape', - val: quote - }); - } - - var tok = advanceTo(this.input, quote); - this.consume(tok.len); - - return pos({ - type: 'quoted', - val: tok.esc - }); - }) - - /** - * Negations: "!" - */ - - .capture('not', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(this.notRegex || /^!+/); - if (!m) return; - var val = m[0]; - - var isNegated = isOdd(val.length); - if (parsed === '' && !isNegated) { - val = ''; - } - - // if nothing has been parsed, we know `!` is at the start, - // so we need to wrap the result in a negation regex - if (parsed === '' && isNegated && this.options.nonegate !== true) { - this.bos.val = '(?!^(?:'; - this.append = ')$).*'; - val = ''; - } - return pos({ - type: 'not', - val: val - }); - }) - - /** - * Dot: "." - */ - - .capture('dot', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\.+/); - if (!m) return; - - var val = m[0]; - this.state.dot = val === '.' && (parsed === '' || parsed.slice(-1) === '/'); - - return pos({ - type: 'dot', - dotfiles: this.state.dot, - val: val - }); - }) - - /** - * Plus: "+" - */ - - .capture('plus', /^\+(?!\()/) - - /** - * Question mark: "?" - */ - - .capture('qmark', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\?+(?!\()/); - if (!m) return; - - this.state.metachar = true; - this.state.qmark = true; - - return pos({ - type: 'qmark', - parsed: parsed, - val: m[0] - }); - }) - - /** - * Globstar: "**" - */ - - .capture('globstar', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\*{2}(?![*(])(?=[,)/]|$)/); - if (!m) return; - - var type = opts.noglobstar !== true ? 'globstar' : 'star'; - var node = pos({type: type, parsed: parsed}); - this.state.metachar = true; - - while (this.input.slice(0, 4) === '/**/') { - this.input = this.input.slice(3); - } - - node.isInside = { - brace: this.isInside('brace'), - paren: this.isInside('paren') - }; - - if (type === 'globstar') { - this.state.globstar = true; - node.val = '**'; - - } else { - this.state.star = true; - node.val = '*'; - } - - return node; - }) - - /** - * Star: "*" - */ - - .capture('star', function() { - var pos = this.position(); - var starRe = /^(?:\*(?![*(])|[*]{3,}(?!\()|[*]{2}(?![(/]|$)|\*(?=\*\())/; - var m = this.match(starRe); - if (!m) return; - - this.state.metachar = true; - this.state.star = true; - return pos({ - type: 'star', - val: m[0] - }); - }) - - /** - * Slash: "/" - */ - - .capture('slash', function() { - var pos = this.position(); - var m = this.match(/^\//); - if (!m) return; - - this.state.slashes++; - return pos({ - type: 'slash', - val: m[0] - }); - }) - - /** - * Backslash: "\\" - */ - - .capture('backslash', function() { - var pos = this.position(); - var m = this.match(/^\\(?![*+?(){}[\]'"])/); - if (!m) return; - - var val = m[0]; - - if (this.isInside('bracket')) { - val = '\\'; - } else if (val.length > 1) { - val = '\\\\'; - } - - return pos({ - type: 'backslash', - val: val - }); - }) - - /** - * Square: "[.]" - */ - - .capture('square', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(/^\[([^!^\\])\]/); - if (!m) return; - - return pos({ - type: 'square', - val: m[1] - }); - }) - - /** - * Brackets: "[...]" (basic, this can be overridden by other parsers) - */ - - .capture('bracket', function() { - var pos = this.position(); - var m = this.match(/^(?:\[([!^]?)([^\]]+|\]-)(\]|[^*+?]+)|\[)/); - if (!m) return; - - var val = m[0]; - var negated = m[1] ? '^' : ''; - var inner = (m[2] || '').replace(/\\\\+/, '\\\\'); - var close = m[3] || ''; - - if (m[2] && inner.length < m[2].length) { - val = val.replace(/\\\\+/, '\\\\'); - } - - var esc = this.input.slice(0, 2); - if (inner === '' && esc === '\\]') { - inner += esc; - this.consume(2); - - var str = this.input; - var idx = -1; - var ch; - - while ((ch = str[++idx])) { - this.consume(1); - if (ch === ']') { - close = ch; - break; - } - inner += ch; - } - } - - return pos({ - type: 'bracket', - val: val, - escaped: close !== ']', - negated: negated, - inner: inner, - close: close - }); - }) - - /** - * Text - */ - - .capture('text', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(not); - if (!m || !m[0]) return; - - return pos({ - type: 'text', - val: m[0] - }); - }); - - /** - * Allow custom parsers to be passed on options - */ - - if (options && typeof options.parsers === 'function') { - options.parsers(nanomatch.parser); - } -}; - -/** - * Advance to the next non-escaped character - */ - -function advanceTo(input, endChar) { - var ch = input.charAt(0); - var tok = { len: 1, val: '', esc: '' }; - var idx = 0; - - function advance() { - if (ch !== '\\') { - tok.esc += '\\' + ch; - tok.val += ch; - } - - ch = input.charAt(++idx); - tok.len++; - - if (ch === '\\') { - advance(); - advance(); - } - } - - while (ch && ch !== endChar) { - advance(); - } - return tok; -} - -/** - * Create text regex - */ - -function createTextRegex(pattern) { - if (cached) return cached; - var opts = {contains: true, strictClose: false}; - var not = regexNot.create(pattern, opts); - var re = toRegex('^(?:[*]\\((?=.)|' + not + ')', opts); - return (cached = re); -} - -/** - * Expose negation string - */ - -module.exports.not = NOT_REGEX; - - -/***/ }), -/* 847 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-odd - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isNumber = __webpack_require__(848); - -module.exports = function isOdd(i) { - if (!isNumber(i)) { - throw new TypeError('is-odd expects a number.'); - } - if (Number(i) !== Math.floor(i)) { - throw new RangeError('is-odd expects an integer.'); - } - return !!(~~i & 1); -}; - - -/***/ }), -/* 848 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-number - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function isNumber(num) { - var type = typeof num; - - if (type === 'string' || num instanceof String) { - // an empty string would be coerced to true with the below logic - if (!num.trim()) return false; - } else if (type !== 'number' && !(num instanceof Number)) { - return false; - } - - return (num - num + 1) >= 0; -}; - - -/***/ }), -/* 849 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = new (__webpack_require__(850))(); - - -/***/ }), -/* 850 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * fragment-cache - * - * Copyright (c) 2016-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var MapCache = __webpack_require__(828); - -/** - * Create a new `FragmentCache` with an optional object to use for `caches`. - * - * ```js - * var fragment = new FragmentCache(); - * ``` - * @name FragmentCache - * @param {String} `cacheName` - * @return {Object} Returns the [map-cache][] instance. - * @api public - */ - -function FragmentCache(caches) { - this.caches = caches || {}; -} - -/** - * Prototype - */ - -FragmentCache.prototype = { - - /** - * Get cache `name` from the `fragment.caches` object. Creates a new - * `MapCache` if it doesn't already exist. - * - * ```js - * var cache = fragment.cache('files'); - * console.log(fragment.caches.hasOwnProperty('files')); - * //=> true - * ``` - * @name .cache - * @param {String} `cacheName` - * @return {Object} Returns the [map-cache][] instance. - * @api public - */ - - cache: function(cacheName) { - return this.caches[cacheName] || (this.caches[cacheName] = new MapCache()); - }, - - /** - * Set a value for property `key` on cache `name` - * - * ```js - * fragment.set('files', 'somefile.js', new File({path: 'somefile.js'})); - * ``` - * @name .set - * @param {String} `name` - * @param {String} `key` Property name to set - * @param {any} `val` The value of `key` - * @return {Object} The cache instance for chaining - * @api public - */ - - set: function(cacheName, key, val) { - var cache = this.cache(cacheName); - cache.set(key, val); - return cache; - }, - - /** - * Returns true if a non-undefined value is set for `key` on fragment cache `name`. - * - * ```js - * var cache = fragment.cache('files'); - * cache.set('somefile.js'); - * - * console.log(cache.has('somefile.js')); - * //=> true - * - * console.log(cache.has('some-other-file.js')); - * //=> false - * ``` - * @name .has - * @param {String} `name` Cache name - * @param {String} `key` Optionally specify a property to check for on cache `name` - * @return {Boolean} - * @api public - */ - - has: function(cacheName, key) { - return typeof this.get(cacheName, key) !== 'undefined'; - }, - - /** - * Get `name`, or if specified, the value of `key`. Invokes the [cache]() method, - * so that cache `name` will be created it doesn't already exist. If `key` is not passed, - * the entire cache (`name`) is returned. - * - * ```js - * var Vinyl = require('vinyl'); - * var cache = fragment.cache('files'); - * cache.set('somefile.js', new Vinyl({path: 'somefile.js'})); - * console.log(cache.get('somefile.js')); - * //=> - * ``` - * @name .get - * @param {String} `name` - * @return {Object} Returns cache `name`, or the value of `key` if specified - * @api public - */ - - get: function(name, key) { - var cache = this.cache(name); - if (typeof key === 'string') { - return cache.get(key); - } - return cache; - } -}; - -/** - * Expose `FragmentCache` - */ - -exports = module.exports = FragmentCache; - - -/***/ }), -/* 851 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = module.exports; -var path = __webpack_require__(16); - -/** - * Module dependencies - */ - -var isWindows = __webpack_require__(852)(); -var Snapdragon = __webpack_require__(768); -utils.define = __webpack_require__(853); -utils.diff = __webpack_require__(854); -utils.extend = __webpack_require__(843); -utils.pick = __webpack_require__(855); -utils.typeOf = __webpack_require__(856); -utils.unique = __webpack_require__(741); - -/** - * Returns true if the given value is effectively an empty string - */ - -utils.isEmptyString = function(val) { - return String(val) === '' || String(val) === './'; -}; - -/** - * Returns true if the platform is windows, or `path.sep` is `\\`. - * This is defined as a function to allow `path.sep` to be set in unit tests, - * or by the user, if there is a reason to do so. - * @return {Boolean} - */ - -utils.isWindows = function() { - return path.sep === '\\' || isWindows === true; -}; - -/** - * Return the last element from an array - */ - -utils.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; - -/** - * Get the `Snapdragon` instance to use - */ - -utils.instantiate = function(ast, options) { - var snapdragon; - // if an instance was created by `.parse`, use that instance - if (utils.typeOf(ast) === 'object' && ast.snapdragon) { - snapdragon = ast.snapdragon; - // if the user supplies an instance on options, use that instance - } else if (utils.typeOf(options) === 'object' && options.snapdragon) { - snapdragon = options.snapdragon; - // create a new instance - } else { - snapdragon = new Snapdragon(options); - } - - utils.define(snapdragon, 'parse', function(str, options) { - var parsed = Snapdragon.prototype.parse.call(this, str, options); - parsed.input = str; - - // escape unmatched brace/bracket/parens - var last = this.parser.stack.pop(); - if (last && this.options.strictErrors !== true) { - var open = last.nodes[0]; - var inner = last.nodes[1]; - if (last.type === 'bracket') { - if (inner.val.charAt(0) === '[') { - inner.val = '\\' + inner.val; - } - - } else { - open.val = '\\' + open.val; - var sibling = open.parent.nodes[1]; - if (sibling.type === 'star') { - sibling.loose = true; - } - } - } - - // add non-enumerable parser reference - utils.define(parsed, 'parser', this.parser); - return parsed; - }); - - return snapdragon; -}; - -/** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ - -utils.createKey = function(pattern, options) { - if (typeof options === 'undefined') { - return pattern; - } - var key = pattern; - for (var prop in options) { - if (options.hasOwnProperty(prop)) { - key += ';' + prop + '=' + String(options[prop]); - } - } - return key; -}; - -/** - * Cast `val` to an array - * @return {Array} - */ - -utils.arrayify = function(val) { - if (typeof val === 'string') return [val]; - return val ? (Array.isArray(val) ? val : [val]) : []; -}; - -/** - * Return true if `val` is a non-empty string - */ - -utils.isString = function(val) { - return typeof val === 'string'; -}; - -/** - * Return true if `val` is a non-empty string - */ - -utils.isRegex = function(val) { - return utils.typeOf(val) === 'regexp'; -}; - -/** - * Return true if `val` is a non-empty string - */ - -utils.isObject = function(val) { - return utils.typeOf(val) === 'object'; -}; - -/** - * Escape regex characters in the given string - */ - -utils.escapeRegex = function(str) { - return str.replace(/[-[\]{}()^$|*+?.\\/\s]/g, '\\$&'); -}; - -/** - * Combines duplicate characters in the provided `input` string. - * @param {String} `input` - * @returns {String} - */ - -utils.combineDupes = function(input, patterns) { - patterns = utils.arrayify(patterns).join('|').split('|'); - patterns = patterns.map(function(s) { - return s.replace(/\\?([+*\\/])/g, '\\$1'); - }); - var substr = patterns.join('|'); - var regex = new RegExp('(' + substr + ')(?=\\1)', 'g'); - return input.replace(regex, ''); -}; - -/** - * Returns true if the given `str` has special characters - */ - -utils.hasSpecialChars = function(str) { - return /(?:(?:(^|\/)[!.])|[*?+()|[\]{}]|[+@]\()/.test(str); -}; - -/** - * Normalize slashes in the given filepath. - * - * @param {String} `filepath` - * @return {String} - */ - -utils.toPosixPath = function(str) { - return str.replace(/\\+/g, '/'); -}; - -/** - * Strip backslashes before special characters in a string. - * - * @param {String} `str` - * @return {String} - */ - -utils.unescape = function(str) { - return utils.toPosixPath(str.replace(/\\(?=[*+?!.])/g, '')); -}; - -/** - * Strip the drive letter from a windows filepath - * @param {String} `fp` - * @return {String} - */ - -utils.stripDrive = function(fp) { - return utils.isWindows() ? fp.replace(/^[a-z]:[\\/]+?/i, '/') : fp; -}; - -/** - * Strip the prefix from a filepath - * @param {String} `fp` - * @return {String} - */ - -utils.stripPrefix = function(str) { - if (str.charAt(0) === '.' && (str.charAt(1) === '/' || str.charAt(1) === '\\')) { - return str.slice(2); - } - return str; -}; - -/** - * Returns true if `str` is a common character that doesn't need - * to be processed to be used for matching. - * @param {String} `str` - * @return {Boolean} - */ - -utils.isSimpleChar = function(str) { - return str.trim() === '' || str === '.'; -}; - -/** - * Returns true if the given str is an escaped or - * unescaped path character - */ - -utils.isSlash = function(str) { - return str === '/' || str === '\\/' || str === '\\' || str === '\\\\'; -}; - -/** - * Returns a function that returns true if the given - * pattern matches or contains a `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ - -utils.matchPath = function(pattern, options) { - return (options && options.contains) - ? utils.containsPattern(pattern, options) - : utils.equalsPattern(pattern, options); -}; - -/** - * Returns true if the given (original) filepath or unixified path are equal - * to the given pattern. - */ - -utils._equals = function(filepath, unixPath, pattern) { - return pattern === filepath || pattern === unixPath; -}; - -/** - * Returns true if the given (original) filepath or unixified path contain - * the given pattern. - */ - -utils._contains = function(filepath, unixPath, pattern) { - return filepath.indexOf(pattern) !== -1 || unixPath.indexOf(pattern) !== -1; -}; - -/** - * Returns a function that returns true if the given - * pattern is the same as a given `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ - -utils.equalsPattern = function(pattern, options) { - var unixify = utils.unixify(options); - options = options || {}; - - return function fn(filepath) { - var equal = utils._equals(filepath, unixify(filepath), pattern); - if (equal === true || options.nocase !== true) { - return equal; - } - var lower = filepath.toLowerCase(); - return utils._equals(lower, unixify(lower), pattern); - }; -}; - -/** - * Returns a function that returns true if the given - * pattern contains a `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ - -utils.containsPattern = function(pattern, options) { - var unixify = utils.unixify(options); - options = options || {}; - - return function(filepath) { - var contains = utils._contains(filepath, unixify(filepath), pattern); - if (contains === true || options.nocase !== true) { - return contains; - } - var lower = filepath.toLowerCase(); - return utils._contains(lower, unixify(lower), pattern); - }; -}; - -/** - * Returns a function that returns true if the given - * regex matches the `filename` of a file path. - * - * @param {RegExp} `re` Matching regex - * @return {Function} - */ - -utils.matchBasename = function(re) { - return function(filepath) { - return re.test(filepath) || re.test(path.basename(filepath)); - }; -}; - -/** - * Returns the given value unchanced. - * @return {any} - */ - -utils.identity = function(val) { - return val; -}; - -/** - * Determines the filepath to return based on the provided options. - * @return {any} - */ - -utils.value = function(str, unixify, options) { - if (options && options.unixify === false) { - return str; - } - if (options && typeof options.unixify === 'function') { - return options.unixify(str); - } - return unixify(str); -}; - -/** - * Returns a function that normalizes slashes in a string to forward - * slashes, strips `./` from beginning of paths, and optionally unescapes - * special characters. - * @return {Function} - */ - -utils.unixify = function(options) { - var opts = options || {}; - return function(filepath) { - if (opts.stripPrefix !== false) { - filepath = utils.stripPrefix(filepath); - } - if (opts.unescape === true) { - filepath = utils.unescape(filepath); - } - if (opts.unixify === true || utils.isWindows()) { - filepath = utils.toPosixPath(filepath); - } - return filepath; - }; -}; - - -/***/ }), -/* 852 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! - * is-windows - * - * Copyright © 2015-2018, Jon Schlinkert. - * Released under the MIT License. - */ - -(function(factory) { - if (exports && typeof exports === 'object' && typeof module !== 'undefined') { - module.exports = factory(); - } else if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), - __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? - (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else {} -})(function() { - 'use strict'; - return function isWindows() { - return process && (process.platform === 'win32' || /^(msys|cygwin)$/.test(process.env.OSTYPE)); - }; -}); - - -/***/ }), -/* 853 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015-2018, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isobject = __webpack_require__(748); -var isDescriptor = __webpack_require__(760); -var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) - ? Reflect.defineProperty - : Object.defineProperty; - -module.exports = function defineProperty(obj, key, val) { - if (!isobject(obj) && typeof obj !== 'function' && !Array.isArray(obj)) { - throw new TypeError('expected an object, function, or array'); - } - - if (typeof key !== 'string') { - throw new TypeError('expected "key" to be a string'); - } - - if (isDescriptor(val)) { - define(obj, key, val); - return obj; - } - - define(obj, key, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); - - return obj; -}; - - -/***/ }), -/* 854 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * arr-diff - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function diff(arr/*, arrays*/) { - var len = arguments.length; - var idx = 0; - while (++idx < len) { - arr = diffArray(arr, arguments[idx]); - } - return arr; -}; - -function diffArray(one, two) { - if (!Array.isArray(two)) { - return one.slice(); - } - - var tlen = two.length - var olen = one.length; - var idx = -1; - var arr = []; - - while (++idx < olen) { - var ele = one[idx]; - - var hasEle = false; - for (var i = 0; i < tlen; i++) { - var val = two[i]; - - if (ele === val) { - hasEle = true; - break; - } - } - - if (hasEle === false) { - arr.push(ele); - } - } - return arr; -} - - -/***/ }), -/* 855 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * object.pick - * - * Copyright (c) 2014-2015 Jon Schlinkert, contributors. - * Licensed under the MIT License - */ - - - -var isObject = __webpack_require__(748); - -module.exports = function pick(obj, keys) { - if (!isObject(obj) && typeof obj !== 'function') { - return {}; - } - - var res = {}; - if (typeof keys === 'string') { - if (keys in obj) { - res[keys] = obj[keys]; - } - return res; - } - - var len = keys.length; - var idx = -1; - - while (++idx < len) { - var key = keys[idx]; - if (key in obj) { - res[key] = obj[key]; - } - } - return res; -}; - - -/***/ }), -/* 856 */ -/***/ (function(module, exports) { - -var toString = Object.prototype.toString; - -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; - - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; - } - - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; - - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; - - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; - - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; - - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; - - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; - } - - if (isGeneratorObj(val)) { - return 'generator'; - } - - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; - } - - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); -}; - -function ctorName(val) { - return typeof val.constructor === 'function' ? val.constructor.name : null; -} - -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} - -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} - -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; -} - -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; -} - -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; -} - -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} - -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; - } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; - } - } - return false; -} - -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ - -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); - } - return false; -} - - -/***/ }), -/* 857 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Module dependencies - */ - -var extend = __webpack_require__(738); -var unique = __webpack_require__(741); -var toRegex = __webpack_require__(729); - -/** - * Local dependencies - */ - -var compilers = __webpack_require__(858); -var parsers = __webpack_require__(869); -var Extglob = __webpack_require__(872); -var utils = __webpack_require__(871); -var MAX_LENGTH = 1024 * 64; - -/** - * Convert the given `extglob` pattern into a regex-compatible string. Returns - * an object with the compiled result and the parsed AST. - * - * ```js - * var extglob = require('extglob'); - * console.log(extglob('*.!(*a)')); - * //=> '(?!\\.)[^/]*?\\.(?!(?!\\.)[^/]*?a\\b).*?' - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {String} - * @api public - */ - -function extglob(pattern, options) { - return extglob.create(pattern, options).output; -} - -/** - * Takes an array of strings and an extglob pattern and returns a new - * array that contains only the strings that match the pattern. - * - * ```js - * var extglob = require('extglob'); - * console.log(extglob.match(['a.a', 'a.b', 'a.c'], '*.!(*a)')); - * //=> ['a.b', 'a.c'] - * ``` - * @param {Array} `list` Array of strings to match - * @param {String} `pattern` Extglob pattern - * @param {Object} `options` - * @return {Array} Returns an array of matches - * @api public - */ - -extglob.match = function(list, pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - list = utils.arrayify(list); - var isMatch = extglob.matcher(pattern, options); - var len = list.length; - var idx = -1; - var matches = []; - - while (++idx < len) { - var ele = list[idx]; - - if (isMatch(ele)) { - matches.push(ele); - } - } - - // if no options were passed, uniquify results and return - if (typeof options === 'undefined') { - return unique(matches); - } - - if (matches.length === 0) { - if (options.failglob === true) { - throw new Error('no matches found for "' + pattern + '"'); - } - if (options.nonull === true || options.nullglob === true) { - return [pattern.split('\\').join('')]; - } - } - - return options.nodupes !== false ? unique(matches) : matches; -}; - -/** - * Returns true if the specified `string` matches the given - * extglob `pattern`. - * - * ```js - * var extglob = require('extglob'); - * - * console.log(extglob.isMatch('a.a', '*.!(*a)')); - * //=> false - * console.log(extglob.isMatch('a.b', '*.!(*a)')); - * //=> true - * ``` - * @param {String} `string` String to match - * @param {String} `pattern` Extglob pattern - * @param {String} `options` - * @return {Boolean} - * @api public - */ - -extglob.isMatch = function(str, pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - if (typeof str !== 'string') { - throw new TypeError('expected a string'); - } - - if (pattern === str) { - return true; - } - - if (pattern === '' || pattern === ' ' || pattern === '.') { - return pattern === str; - } - - var isMatch = utils.memoize('isMatch', pattern, options, extglob.matcher); - return isMatch(str); -}; - -/** - * Returns true if the given `string` contains the given pattern. Similar to `.isMatch` but - * the pattern can match any part of the string. - * - * ```js - * var extglob = require('extglob'); - * console.log(extglob.contains('aa/bb/cc', '*b')); - * //=> true - * console.log(extglob.contains('aa/bb/cc', '*d')); - * //=> false - * ``` - * @param {String} `str` The string to match. - * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` - * @return {Boolean} Returns true if the patter matches any part of `str`. - * @api public - */ - -extglob.contains = function(str, pattern, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string'); - } - - if (pattern === '' || pattern === ' ' || pattern === '.') { - return pattern === str; - } - - var opts = extend({}, options, {contains: true}); - opts.strictClose = false; - opts.strictOpen = false; - return extglob.isMatch(str, pattern, opts); -}; - -/** - * Takes an extglob pattern and returns a matcher function. The returned - * function takes the string to match as its only argument. - * - * ```js - * var extglob = require('extglob'); - * var isMatch = extglob.matcher('*.!(*a)'); - * - * console.log(isMatch('a.a')); - * //=> false - * console.log(isMatch('a.b')); - * //=> true - * ``` - * @param {String} `pattern` Extglob pattern - * @param {String} `options` - * @return {Boolean} - * @api public - */ - -extglob.matcher = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - function matcher() { - var re = extglob.makeRe(pattern, options); - return function(str) { - return re.test(str); - }; - } - - return utils.memoize('matcher', pattern, options, matcher); -}; - -/** - * Convert the given `extglob` pattern into a regex-compatible string. Returns - * an object with the compiled result and the parsed AST. - * - * ```js - * var extglob = require('extglob'); - * console.log(extglob.create('*.!(*a)').output); - * //=> '(?!\\.)[^/]*?\\.(?!(?!\\.)[^/]*?a\\b).*?' - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {String} - * @api public - */ - -extglob.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - function create() { - var ext = new Extglob(options); - var ast = ext.parse(pattern, options); - return ext.compile(ast, options); - } - - return utils.memoize('create', pattern, options, create); -}; - -/** - * Returns an array of matches captured by `pattern` in `string`, or `null` - * if the pattern did not match. - * - * ```js - * var extglob = require('extglob'); - * extglob.capture(pattern, string[, options]); - * - * console.log(extglob.capture('test/*.js', 'test/foo.js')); - * //=> ['foo'] - * console.log(extglob.capture('test/*.js', 'foo/bar.css')); - * //=> null - * ``` - * @param {String} `pattern` Glob pattern to use for matching. - * @param {String} `string` String to match - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns an array of captures if the string matches the glob pattern, otherwise `null`. - * @api public - */ - -extglob.capture = function(pattern, str, options) { - var re = extglob.makeRe(pattern, extend({capture: true}, options)); - - function match() { - return function(string) { - var match = re.exec(string); - if (!match) { - return null; - } - - return match.slice(1); - }; - } - - var capture = utils.memoize('capture', pattern, options, match); - return capture(str); -}; - -/** - * Create a regular expression from the given `pattern` and `options`. - * - * ```js - * var extglob = require('extglob'); - * var re = extglob.makeRe('*.!(*a)'); - * console.log(re); - * //=> /^[^\/]*?\.(?![^\/]*?a)[^\/]*?$/ - * ``` - * @param {String} `pattern` The pattern to convert to regex. - * @param {Object} `options` - * @return {RegExp} - * @api public - */ - -extglob.makeRe = function(pattern, options) { - if (pattern instanceof RegExp) { - return pattern; - } - - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - if (pattern.length > MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); - } - - function makeRe() { - var opts = extend({strictErrors: false}, options); - if (opts.strictErrors === true) opts.strict = true; - var res = extglob.create(pattern, opts); - return toRegex(res.output, opts); - } - - var regex = utils.memoize('makeRe', pattern, options, makeRe); - if (regex.source.length > MAX_LENGTH) { - throw new SyntaxError('potentially malicious regex detected'); - } - - return regex; -}; - -/** - * Cache - */ - -extglob.cache = utils.cache; -extglob.clearCache = function() { - extglob.cache.__data__ = {}; -}; - -/** - * Expose `Extglob` constructor, parsers and compilers - */ - -extglob.Extglob = Extglob; -extglob.compilers = compilers; -extglob.parsers = parsers; - -/** - * Expose `extglob` - * @type {Function} - */ - -module.exports = extglob; - - -/***/ }), -/* 858 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var brackets = __webpack_require__(859); - -/** - * Extglob compilers - */ - -module.exports = function(extglob) { - function star() { - if (typeof extglob.options.star === 'function') { - return extglob.options.star.apply(this, arguments); - } - if (typeof extglob.options.star === 'string') { - return extglob.options.star; - } - return '.*?'; - } - - /** - * Use `expand-brackets` compilers - */ - - extglob.use(brackets.compilers); - extglob.compiler - - /** - * Escaped: "\\*" - */ - - .set('escape', function(node) { - return this.emit(node.val, node); - }) - - /** - * Dot: "." - */ - - .set('dot', function(node) { - return this.emit('\\' + node.val, node); - }) - - /** - * Question mark: "?" - */ - - .set('qmark', function(node) { - var val = '[^\\\\/.]'; - var prev = this.prev(); - - if (node.parsed.slice(-1) === '(') { - var ch = node.rest.charAt(0); - if (ch !== '!' && ch !== '=' && ch !== ':') { - return this.emit(val, node); - } - return this.emit(node.val, node); - } - - if (prev.type === 'text' && prev.val) { - return this.emit(val, node); - } - - if (node.val.length > 1) { - val += '{' + node.val.length + '}'; - } - return this.emit(val, node); - }) - - /** - * Plus: "+" - */ - - .set('plus', function(node) { - var prev = node.parsed.slice(-1); - if (prev === ']' || prev === ')') { - return this.emit(node.val, node); - } - var ch = this.output.slice(-1); - if (!this.output || (/[?*+]/.test(ch) && node.parent.type !== 'bracket')) { - return this.emit('\\+', node); - } - if (/\w/.test(ch) && !node.inside) { - return this.emit('+\\+?', node); - } - return this.emit('+', node); - }) - - /** - * Star: "*" - */ - - .set('star', function(node) { - var prev = this.prev(); - var prefix = prev.type !== 'text' && prev.type !== 'escape' - ? '(?!\\.)' - : ''; - - return this.emit(prefix + star.call(this, node), node); - }) - - /** - * Parens - */ - - .set('paren', function(node) { - return this.mapVisit(node.nodes); - }) - .set('paren.open', function(node) { - var capture = this.options.capture ? '(' : ''; - - switch (node.parent.prefix) { - case '!': - case '^': - return this.emit(capture + '(?:(?!(?:', node); - case '*': - case '+': - case '?': - case '@': - return this.emit(capture + '(?:', node); - default: { - var val = node.val; - if (this.options.bash === true) { - val = '\\' + val; - } else if (!this.options.capture && val === '(' && node.parent.rest[0] !== '?') { - val += '?:'; - } - - return this.emit(val, node); - } - } - }) - .set('paren.close', function(node) { - var capture = this.options.capture ? ')' : ''; - - switch (node.prefix) { - case '!': - case '^': - var prefix = /^(\)|$)/.test(node.rest) ? '$' : ''; - var str = star.call(this, node); - - // if the extglob has a slash explicitly defined, we know the user wants - // to match slashes, so we need to ensure the "star" regex allows for it - if (node.parent.hasSlash && !this.options.star && this.options.slash !== false) { - str = '.*?'; - } - - return this.emit(prefix + ('))' + str + ')') + capture, node); - case '*': - case '+': - case '?': - return this.emit(')' + node.prefix + capture, node); - case '@': - return this.emit(')' + capture, node); - default: { - var val = (this.options.bash === true ? '\\' : '') + ')'; - return this.emit(val, node); - } - } - }) - - /** - * Text - */ - - .set('text', function(node) { - var val = node.val.replace(/[\[\]]/g, '\\$&'); - return this.emit(val, node); - }); -}; - - -/***/ }), -/* 859 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Local dependencies - */ - -var compilers = __webpack_require__(860); -var parsers = __webpack_require__(862); - -/** - * Module dependencies - */ - -var debug = __webpack_require__(864)('expand-brackets'); -var extend = __webpack_require__(738); -var Snapdragon = __webpack_require__(768); -var toRegex = __webpack_require__(729); - -/** - * Parses the given POSIX character class `pattern` and returns a - * string that can be used for creating regular expressions for matching. - * - * @param {String} `pattern` - * @param {Object} `options` - * @return {Object} - * @api public - */ - -function brackets(pattern, options) { - debug('initializing from <%s>', __filename); - var res = brackets.create(pattern, options); - return res.output; -} - -/** - * Takes an array of strings and a POSIX character class pattern, and returns a new - * array with only the strings that matched the pattern. - * - * ```js - * var brackets = require('expand-brackets'); - * console.log(brackets.match(['1', 'a', 'ab'], '[[:alpha:]]')); - * //=> ['a'] - * - * console.log(brackets.match(['1', 'a', 'ab'], '[[:alpha:]]+')); - * //=> ['a', 'ab'] - * ``` - * @param {Array} `arr` Array of strings to match - * @param {String} `pattern` POSIX character class pattern(s) - * @param {Object} `options` - * @return {Array} - * @api public - */ - -brackets.match = function(arr, pattern, options) { - arr = [].concat(arr); - var opts = extend({}, options); - var isMatch = brackets.matcher(pattern, opts); - var len = arr.length; - var idx = -1; - var res = []; - - while (++idx < len) { - var ele = arr[idx]; - if (isMatch(ele)) { - res.push(ele); - } - } - - if (res.length === 0) { - if (opts.failglob === true) { - throw new Error('no matches found for "' + pattern + '"'); - } - - if (opts.nonull === true || opts.nullglob === true) { - return [pattern.split('\\').join('')]; - } - } - return res; -}; - -/** - * Returns true if the specified `string` matches the given - * brackets `pattern`. - * - * ```js - * var brackets = require('expand-brackets'); - * - * console.log(brackets.isMatch('a.a', '[[:alpha:]].[[:alpha:]]')); - * //=> true - * console.log(brackets.isMatch('1.2', '[[:alpha:]].[[:alpha:]]')); - * //=> false - * ``` - * @param {String} `string` String to match - * @param {String} `pattern` Poxis pattern - * @param {String} `options` - * @return {Boolean} - * @api public - */ - -brackets.isMatch = function(str, pattern, options) { - return brackets.matcher(pattern, options)(str); -}; - -/** - * Takes a POSIX character class pattern and returns a matcher function. The returned - * function takes the string to match as its only argument. - * - * ```js - * var brackets = require('expand-brackets'); - * var isMatch = brackets.matcher('[[:lower:]].[[:upper:]]'); - * - * console.log(isMatch('a.a')); - * //=> false - * console.log(isMatch('a.A')); - * //=> true - * ``` - * @param {String} `pattern` Poxis pattern - * @param {String} `options` - * @return {Boolean} - * @api public - */ - -brackets.matcher = function(pattern, options) { - var re = brackets.makeRe(pattern, options); - return function(str) { - return re.test(str); - }; -}; - -/** - * Create a regular expression from the given `pattern`. - * - * ```js - * var brackets = require('expand-brackets'); - * var re = brackets.makeRe('[[:alpha:]]'); - * console.log(re); - * //=> /^(?:[a-zA-Z])$/ - * ``` - * @param {String} `pattern` The pattern to convert to regex. - * @param {Object} `options` - * @return {RegExp} - * @api public - */ - -brackets.makeRe = function(pattern, options) { - var res = brackets.create(pattern, options); - var opts = extend({strictErrors: false}, options); - return toRegex(res.output, opts); -}; - -/** - * Parses the given POSIX character class `pattern` and returns an object - * with the compiled `output` and optional source `map`. - * - * ```js - * var brackets = require('expand-brackets'); - * console.log(brackets('[[:alpha:]]')); - * // { options: { source: 'string' }, - * // input: '[[:alpha:]]', - * // state: {}, - * // compilers: - * // { eos: [Function], - * // noop: [Function], - * // bos: [Function], - * // not: [Function], - * // escape: [Function], - * // text: [Function], - * // posix: [Function], - * // bracket: [Function], - * // 'bracket.open': [Function], - * // 'bracket.inner': [Function], - * // 'bracket.literal': [Function], - * // 'bracket.close': [Function] }, - * // output: '[a-zA-Z]', - * // ast: - * // { type: 'root', - * // errors: [], - * // nodes: [ [Object], [Object], [Object] ] }, - * // parsingErrors: [] } - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {Object} - * @api public - */ - -brackets.create = function(pattern, options) { - var snapdragon = (options && options.snapdragon) || new Snapdragon(options); - compilers(snapdragon); - parsers(snapdragon); - - var ast = snapdragon.parse(pattern, options); - ast.input = pattern; - var res = snapdragon.compile(ast, options); - res.input = pattern; - return res; -}; - -/** - * Expose `brackets` constructor, parsers and compilers - */ - -brackets.compilers = compilers; -brackets.parsers = parsers; - -/** - * Expose `brackets` - * @type {Function} - */ - -module.exports = brackets; - - -/***/ }), -/* 860 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var posix = __webpack_require__(861); - -module.exports = function(brackets) { - brackets.compiler - - /** - * Escaped characters - */ - - .set('escape', function(node) { - return this.emit('\\' + node.val.replace(/^\\/, ''), node); - }) - - /** - * Text - */ - - .set('text', function(node) { - return this.emit(node.val.replace(/([{}])/g, '\\$1'), node); - }) - - /** - * POSIX character classes - */ - - .set('posix', function(node) { - if (node.val === '[::]') { - return this.emit('\\[::\\]', node); - } - - var val = posix[node.inner]; - if (typeof val === 'undefined') { - val = '[' + node.inner + ']'; - } - return this.emit(val, node); - }) - - /** - * Non-posix brackets - */ - - .set('bracket', function(node) { - return this.mapVisit(node.nodes); - }) - .set('bracket.open', function(node) { - return this.emit(node.val, node); - }) - .set('bracket.inner', function(node) { - var inner = node.val; - - if (inner === '[' || inner === ']') { - return this.emit('\\' + node.val, node); - } - if (inner === '^]') { - return this.emit('^\\]', node); - } - if (inner === '^') { - return this.emit('^', node); - } - - if (/-/.test(inner) && !/(\d-\d|\w-\w)/.test(inner)) { - inner = inner.split('-').join('\\-'); - } - - var isNegated = inner.charAt(0) === '^'; - // add slashes to negated brackets, per spec - if (isNegated && inner.indexOf('/') === -1) { - inner += '/'; - } - if (isNegated && inner.indexOf('.') === -1) { - inner += '.'; - } - - // don't unescape `0` (octal literal) - inner = inner.replace(/\\([1-9])/g, '$1'); - return this.emit(inner, node); - }) - .set('bracket.close', function(node) { - var val = node.val.replace(/^\\/, ''); - if (node.parent.escaped === true) { - return this.emit('\\' + val, node); - } - return this.emit(val, node); - }); -}; - - -/***/ }), -/* 861 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * POSIX character classes - */ - -module.exports = { - alnum: 'a-zA-Z0-9', - alpha: 'a-zA-Z', - ascii: '\\x00-\\x7F', - blank: ' \\t', - cntrl: '\\x00-\\x1F\\x7F', - digit: '0-9', - graph: '\\x21-\\x7E', - lower: 'a-z', - print: '\\x20-\\x7E ', - punct: '\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~', - space: ' \\t\\r\\n\\v\\f', - upper: 'A-Z', - word: 'A-Za-z0-9_', - xdigit: 'A-Fa-f0-9' -}; - - -/***/ }), -/* 862 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = __webpack_require__(863); -var define = __webpack_require__(730); - -/** - * Text regex - */ - -var TEXT_REGEX = '(\\[(?=.*\\])|\\])+'; -var not = utils.createRegex(TEXT_REGEX); - -/** - * Brackets parsers - */ - -function parsers(brackets) { - brackets.state = brackets.state || {}; - brackets.parser.sets.bracket = brackets.parser.sets.bracket || []; - brackets.parser - - .capture('escape', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(/^\\(.)/); - if (!m) return; - - return pos({ - type: 'escape', - val: m[0] - }); - }) - - /** - * Text parser - */ - - .capture('text', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(not); - if (!m || !m[0]) return; - - return pos({ - type: 'text', - val: m[0] - }); - }) - - /** - * POSIX character classes: "[[:alpha:][:digits:]]" - */ - - .capture('posix', function() { - var pos = this.position(); - var m = this.match(/^\[:(.*?):\](?=.*\])/); - if (!m) return; - - var inside = this.isInside('bracket'); - if (inside) { - brackets.posix++; - } - - return pos({ - type: 'posix', - insideBracket: inside, - inner: m[1], - val: m[0] - }); - }) - - /** - * Bracket (noop) - */ - - .capture('bracket', function() {}) - - /** - * Open: '[' - */ - - .capture('bracket.open', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\[(?=.*\])/); - if (!m) return; - - var prev = this.prev(); - var last = utils.last(prev.nodes); - - if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { - last.val = last.val.slice(0, last.val.length - 1); - return pos({ - type: 'escape', - val: m[0] - }); - } - - var open = pos({ - type: 'bracket.open', - val: m[0] - }); - - if (last.type === 'bracket.open' || this.isInside('bracket')) { - open.val = '\\' + open.val; - open.type = 'bracket.inner'; - open.escaped = true; - return open; - } - - var node = pos({ - type: 'bracket', - nodes: [open] - }); - - define(node, 'parent', prev); - define(open, 'parent', node); - this.push('bracket', node); - prev.nodes.push(node); - }) - - /** - * Bracket text - */ - - .capture('bracket.inner', function() { - if (!this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(not); - if (!m || !m[0]) return; - - var next = this.input.charAt(0); - var val = m[0]; - - var node = pos({ - type: 'bracket.inner', - val: val - }); - - if (val === '\\\\') { - return node; - } - - var first = val.charAt(0); - var last = val.slice(-1); - - if (first === '!') { - val = '^' + val.slice(1); - } - - if (last === '\\' || (val === '^' && next === ']')) { - val += this.input[0]; - this.consume(1); - } - - node.val = val; - return node; - }) - - /** - * Close: ']' - */ - - .capture('bracket.close', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\]/); - if (!m) return; - - var prev = this.prev(); - var last = utils.last(prev.nodes); - - if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { - last.val = last.val.slice(0, last.val.length - 1); - - return pos({ - type: 'escape', - val: m[0] - }); - } - - var node = pos({ - type: 'bracket.close', - rest: this.input, - val: m[0] - }); - - if (last.type === 'bracket.open') { - node.type = 'bracket.inner'; - node.escaped = true; - return node; - } - - var bracket = this.pop('bracket'); - if (!this.isType(bracket, 'bracket')) { - if (this.options.strict) { - throw new Error('missing opening "["'); - } - node.type = 'bracket.inner'; - node.escaped = true; - return node; - } - - bracket.nodes.push(node); - define(node, 'parent', bracket); - }); -} - -/** - * Brackets parsers - */ - -module.exports = parsers; - -/** - * Expose text regex - */ - -module.exports.TEXT_REGEX = TEXT_REGEX; - - -/***/ }), -/* 863 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var toRegex = __webpack_require__(729); -var regexNot = __webpack_require__(740); -var cached; - -/** - * Get the last element from `array` - * @param {Array} `array` - * @return {*} - */ - -exports.last = function(arr) { - return arr[arr.length - 1]; -}; - -/** - * Create and cache regex to use for text nodes - */ - -exports.createRegex = function(pattern, include) { - if (cached) return cached; - var opts = {contains: true, strictClose: false}; - var not = regexNot.create(pattern, opts); - var re; - - if (typeof include === 'string') { - re = toRegex('^(?:' + include + '|' + not + ')', opts); - } else { - re = toRegex(not, opts); - } - - return (cached = re); -}; - - -/***/ }), -/* 864 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * Detect Electron renderer process, which is node, but we should - * treat as a browser. - */ - -if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(865); -} else { - module.exports = __webpack_require__(868); -} - - -/***/ }), -/* 865 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * This is the web browser implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = __webpack_require__(866); -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; -exports.storage = 'undefined' != typeof chrome - && 'undefined' != typeof chrome.storage - ? chrome.storage.local - : localstorage(); - -/** - * Colors. - */ - -exports.colors = [ - 'lightseagreen', - 'forestgreen', - 'goldenrod', - 'dodgerblue', - 'darkorchid', - 'crimson' -]; - -/** - * Currently only WebKit-based Web Inspectors, Firefox >= v31, - * and the Firebug extension (any Firefox version) are known - * to support "%c" CSS customizations. - * - * TODO: add a `localStorage` variable to explicitly enable/disable colors - */ - -function useColors() { - // NB: In an Electron preload script, document will be defined but not fully - // initialized. Since we know we're in Chrome, we'll just detect this case - // explicitly - if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { - return true; - } - - // is webkit? http://stackoverflow.com/a/16459606/376773 - // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 - return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || - // is firebug? http://stackoverflow.com/a/398120/376773 - (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || - // is firefox >= v31? - // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || - // double check webkit in userAgent just in case we are in a worker - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); -} - -/** - * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. - */ - -exports.formatters.j = function(v) { - try { - return JSON.stringify(v); - } catch (err) { - return '[UnexpectedJSONParseError]: ' + err.message; - } -}; - - -/** - * Colorize log arguments if enabled. - * - * @api public - */ - -function formatArgs(args) { - var useColors = this.useColors; - - args[0] = (useColors ? '%c' : '') - + this.namespace - + (useColors ? ' %c' : ' ') - + args[0] - + (useColors ? '%c ' : ' ') - + '+' + exports.humanize(this.diff); - - if (!useColors) return; - - var c = 'color: ' + this.color; - args.splice(1, 0, c, 'color: inherit') - - // the final "%c" is somewhat tricky, because there could be other - // arguments passed either before or after the %c, so we need to - // figure out the correct index to insert the CSS into - var index = 0; - var lastC = 0; - args[0].replace(/%[a-zA-Z%]/g, function(match) { - if ('%%' === match) return; - index++; - if ('%c' === match) { - // we only are interested in the *last* %c - // (the user may have provided their own) - lastC = index; - } - }); - - args.splice(lastC, 0, c); -} - -/** - * Invokes `console.log()` when available. - * No-op when `console.log` is not a "function". - * - * @api public - */ - -function log() { - // this hackery is required for IE8/9, where - // the `console.log` function doesn't have 'apply' - return 'object' === typeof console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - try { - if (null == namespaces) { - exports.storage.removeItem('debug'); - } else { - exports.storage.debug = namespaces; - } - } catch(e) {} -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - var r; - try { - r = exports.storage.debug; - } catch(e) {} - - // If debug isn't set in LS, and we're in Electron, try to load $DEBUG - if (!r && typeof process !== 'undefined' && 'env' in process) { - r = process.env.DEBUG; - } - - return r; -} - -/** - * Enable namespaces listed in `localStorage.debug` initially. - */ - -exports.enable(load()); - -/** - * Localstorage attempts to return the localstorage. - * - * This is necessary because safari throws - * when a user disables cookies/localstorage - * and you attempt to access it. - * - * @return {LocalStorage} - * @api private - */ - -function localstorage() { - try { - return window.localStorage; - } catch (e) {} -} - - -/***/ }), -/* 866 */ -/***/ (function(module, exports, __webpack_require__) { - - -/** - * This is the common logic for both the Node.js and web browser - * implementations of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; -exports.coerce = coerce; -exports.disable = disable; -exports.enable = enable; -exports.enabled = enabled; -exports.humanize = __webpack_require__(867); - -/** - * The currently active debug mode names, and names to skip. - */ - -exports.names = []; -exports.skips = []; - -/** - * Map of special "%n" handling functions, for the debug "format" argument. - * - * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". - */ - -exports.formatters = {}; - -/** - * Previous log timestamp. - */ - -var prevTime; - -/** - * Select a color. - * @param {String} namespace - * @return {Number} - * @api private - */ - -function selectColor(namespace) { - var hash = 0, i; - - for (i in namespace) { - hash = ((hash << 5) - hash) + namespace.charCodeAt(i); - hash |= 0; // Convert to 32bit integer - } - - return exports.colors[Math.abs(hash) % exports.colors.length]; -} - -/** - * Create a debugger with the given `namespace`. - * - * @param {String} namespace - * @return {Function} - * @api public - */ - -function createDebug(namespace) { - - function debug() { - // disabled? - if (!debug.enabled) return; - - var self = debug; - - // set `diff` timestamp - var curr = +new Date(); - var ms = curr - (prevTime || curr); - self.diff = ms; - self.prev = prevTime; - self.curr = curr; - prevTime = curr; - - // turn the `arguments` into a proper Array - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } - - args[0] = exports.coerce(args[0]); - - if ('string' !== typeof args[0]) { - // anything else let's inspect with %O - args.unshift('%O'); - } - - // apply any `formatters` transformations - var index = 0; - args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { - // if we encounter an escaped % then don't increase the array index - if (match === '%%') return match; - index++; - var formatter = exports.formatters[format]; - if ('function' === typeof formatter) { - var val = args[index]; - match = formatter.call(self, val); - - // now we need to remove `args[index]` since it's inlined in the `format` - args.splice(index, 1); - index--; - } - return match; - }); - - // apply env-specific formatting (colors, etc.) - exports.formatArgs.call(self, args); - - var logFn = debug.log || exports.log || console.log.bind(console); - logFn.apply(self, args); - } - - debug.namespace = namespace; - debug.enabled = exports.enabled(namespace); - debug.useColors = exports.useColors(); - debug.color = selectColor(namespace); - - // env-specific initialization logic for debug instances - if ('function' === typeof exports.init) { - exports.init(debug); - } - - return debug; -} - -/** - * Enables a debug mode by namespaces. This can include modes - * separated by a colon and wildcards. - * - * @param {String} namespaces - * @api public - */ - -function enable(namespaces) { - exports.save(namespaces); - - exports.names = []; - exports.skips = []; - - var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - var len = split.length; - - for (var i = 0; i < len; i++) { - if (!split[i]) continue; // ignore empty strings - namespaces = split[i].replace(/\*/g, '.*?'); - if (namespaces[0] === '-') { - exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); - } else { - exports.names.push(new RegExp('^' + namespaces + '$')); - } - } -} - -/** - * Disable debug output. - * - * @api public - */ - -function disable() { - exports.enable(''); -} - -/** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ - -function enabled(name) { - var i, len; - for (i = 0, len = exports.skips.length; i < len; i++) { - if (exports.skips[i].test(name)) { - return false; - } - } - for (i = 0, len = exports.names.length; i < len; i++) { - if (exports.names[i].test(name)) { - return true; - } - } - return false; -} - -/** - * Coerce `val`. - * - * @param {Mixed} val - * @return {Mixed} - * @api private - */ - -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} - - -/***/ }), -/* 867 */ -/***/ (function(module, exports) { - -/** - * Helpers. - */ - -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; - -/** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @param {String|Number} val - * @param {Object} [options] - * @throws {Error} throw an error if val is not a non-empty string or a number - * @return {String|Number} - * @api public - */ - -module.exports = function(val, options) { - options = options || {}; - var type = typeof val; - if (type === 'string' && val.length > 0) { - return parse(val); - } else if (type === 'number' && isNaN(val) === false) { - return options.long ? fmtLong(val) : fmtShort(val); - } - throw new Error( - 'val is not a non-empty string or a valid number. val=' + - JSON.stringify(val) - ); -}; - -/** - * Parse the given `str` and return milliseconds. - * - * @param {String} str - * @return {Number} - * @api private - */ - -function parse(str) { - str = String(str); - if (str.length > 100) { - return; - } - var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( - str - ); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'yrs': - case 'yr': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'hrs': - case 'hr': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'mins': - case 'min': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 'secs': - case 'sec': - case 's': - return n * s; - case 'milliseconds': - case 'millisecond': - case 'msecs': - case 'msec': - case 'ms': - return n; - default: - return undefined; - } -} - -/** - * Short format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtShort(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; -} - -/** - * Long format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtLong(ms) { - return plural(ms, d, 'day') || - plural(ms, h, 'hour') || - plural(ms, m, 'minute') || - plural(ms, s, 'second') || - ms + ' ms'; -} - -/** - * Pluralization helper. - */ - -function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; - } - return Math.ceil(ms / n) + ' ' + name + 's'; -} - - -/***/ }), -/* 868 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * Module dependencies. - */ - -var tty = __webpack_require__(480); -var util = __webpack_require__(29); - -/** - * This is the Node.js implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = __webpack_require__(866); -exports.init = init; -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; - -/** - * Colors. - */ - -exports.colors = [6, 2, 3, 4, 5, 1]; - -/** - * Build up the default `inspectOpts` object from the environment variables. - * - * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js - */ - -exports.inspectOpts = Object.keys(process.env).filter(function (key) { - return /^debug_/i.test(key); -}).reduce(function (obj, key) { - // camel-case - var prop = key - .substring(6) - .toLowerCase() - .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); - - // coerce string value into JS value - var val = process.env[key]; - if (/^(yes|on|true|enabled)$/i.test(val)) val = true; - else if (/^(no|off|false|disabled)$/i.test(val)) val = false; - else if (val === 'null') val = null; - else val = Number(val); - - obj[prop] = val; - return obj; -}, {}); - -/** - * The file descriptor to write the `debug()` calls to. - * Set the `DEBUG_FD` env variable to override with another value. i.e.: - * - * $ DEBUG_FD=3 node script.js 3>debug.log - */ - -var fd = parseInt(process.env.DEBUG_FD, 10) || 2; - -if (1 !== fd && 2 !== fd) { - util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')() -} - -var stream = 1 === fd ? process.stdout : - 2 === fd ? process.stderr : - createWritableStdioStream(fd); - -/** - * Is stdout a TTY? Colored output is enabled when `true`. - */ - -function useColors() { - return 'colors' in exports.inspectOpts - ? Boolean(exports.inspectOpts.colors) - : tty.isatty(fd); -} - -/** - * Map %o to `util.inspect()`, all on a single line. - */ - -exports.formatters.o = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts) - .split('\n').map(function(str) { - return str.trim() - }).join(' '); -}; - -/** - * Map %o to `util.inspect()`, allowing multiple lines if needed. - */ - -exports.formatters.O = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts); -}; - -/** - * Adds ANSI color escape codes if enabled. - * - * @api public - */ - -function formatArgs(args) { - var name = this.namespace; - var useColors = this.useColors; - - if (useColors) { - var c = this.color; - var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; - - args[0] = prefix + args[0].split('\n').join('\n' + prefix); - args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); - } else { - args[0] = new Date().toUTCString() - + ' ' + name + ' ' + args[0]; - } -} - -/** - * Invokes `util.format()` with the specified arguments and writes to `stream`. - */ - -function log() { - return stream.write(util.format.apply(util, arguments) + '\n'); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - if (null == namespaces) { - // If you set a process.env field to null or undefined, it gets cast to the - // string 'null' or 'undefined'. Just delete instead. - delete process.env.DEBUG; - } else { - process.env.DEBUG = namespaces; - } -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - return process.env.DEBUG; -} - -/** - * Copied from `node/src/node.js`. - * - * XXX: It's lame that node doesn't expose this API out-of-the-box. It also - * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. - */ - -function createWritableStdioStream (fd) { - var stream; - var tty_wrap = process.binding('tty_wrap'); - - // Note stream._type is used for test-module-load-list.js - - switch (tty_wrap.guessHandleType(fd)) { - case 'TTY': - stream = new tty.WriteStream(fd); - stream._type = 'tty'; - - // Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - case 'FILE': - var fs = __webpack_require__(23); - stream = new fs.SyncWriteStream(fd, { autoClose: false }); - stream._type = 'fs'; - break; - - case 'PIPE': - case 'TCP': - var net = __webpack_require__(806); - stream = new net.Socket({ - fd: fd, - readable: false, - writable: true - }); - - // FIXME Should probably have an option in net.Socket to create a - // stream from an existing fd which is writable only. But for now - // we'll just add this hack and set the `readable` member to false. - // Test: ./node test/fixtures/echo.js < /etc/passwd - stream.readable = false; - stream.read = null; - stream._type = 'pipe'; - - // FIXME Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - default: - // Probably an error on in uv_guess_handle() - throw new Error('Implement me. Unknown stream file type!'); - } - - // For supporting legacy API we put the FD here. - stream.fd = fd; - - stream._isStdio = true; - - return stream; -} - -/** - * Init logic for `debug` instances. - * - * Create a new `inspectOpts` object in case `useColors` is set - * differently for a particular `debug` instance. - */ - -function init (debug) { - debug.inspectOpts = {}; - - var keys = Object.keys(exports.inspectOpts); - for (var i = 0; i < keys.length; i++) { - debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; - } -} - -/** - * Enable namespaces listed in `process.env.DEBUG` initially. - */ - -exports.enable(load()); - - -/***/ }), -/* 869 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var brackets = __webpack_require__(859); -var define = __webpack_require__(870); -var utils = __webpack_require__(871); - -/** - * Characters to use in text regex (we want to "not" match - * characters that are matched by other parsers) - */ - -var TEXT_REGEX = '([!@*?+]?\\(|\\)|[*?.+\\\\]|\\[:?(?=.*\\])|:?\\])+'; -var not = utils.createRegex(TEXT_REGEX); - -/** - * Extglob parsers - */ - -function parsers(extglob) { - extglob.state = extglob.state || {}; - - /** - * Use `expand-brackets` parsers - */ - - extglob.use(brackets.parsers); - extglob.parser.sets.paren = extglob.parser.sets.paren || []; - extglob.parser - - /** - * Extglob open: "*(" - */ - - .capture('paren.open', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^([!@*?+])?\(/); - if (!m) return; - - var prev = this.prev(); - var prefix = m[1]; - var val = m[0]; - - var open = pos({ - type: 'paren.open', - parsed: parsed, - val: val - }); - - var node = pos({ - type: 'paren', - prefix: prefix, - nodes: [open] - }); - - // if nested negation extglobs, just cancel them out to simplify - if (prefix === '!' && prev.type === 'paren' && prev.prefix === '!') { - prev.prefix = '@'; - node.prefix = '@'; - } - - define(node, 'rest', this.input); - define(node, 'parsed', parsed); - define(node, 'parent', prev); - define(open, 'parent', node); - - this.push('paren', node); - prev.nodes.push(node); - }) - - /** - * Extglob close: ")" - */ - - .capture('paren.close', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\)/); - if (!m) return; - - var parent = this.pop('paren'); - var node = pos({ - type: 'paren.close', - rest: this.input, - parsed: parsed, - val: m[0] - }); - - if (!this.isType(parent, 'paren')) { - if (this.options.strict) { - throw new Error('missing opening paren: "("'); - } - node.escaped = true; - return node; - } - - node.prefix = parent.prefix; - parent.nodes.push(node); - define(node, 'parent', parent); - }) - - /** - * Escape: "\\." - */ - - .capture('escape', function() { - var pos = this.position(); - var m = this.match(/^\\(.)/); - if (!m) return; - - return pos({ - type: 'escape', - val: m[0], - ch: m[1] - }); - }) - - /** - * Question marks: "?" - */ - - .capture('qmark', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\?+(?!\()/); - if (!m) return; - extglob.state.metachar = true; - return pos({ - type: 'qmark', - rest: this.input, - parsed: parsed, - val: m[0] - }); - }) - - /** - * Character parsers - */ - - .capture('star', /^\*(?!\()/) - .capture('plus', /^\+(?!\()/) - .capture('dot', /^\./) - .capture('text', not); -}; - -/** - * Expose text regex string - */ - -module.exports.TEXT_REGEX = TEXT_REGEX; - -/** - * Extglob parsers - */ - -module.exports = parsers; - - -/***/ }), -/* 870 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isDescriptor = __webpack_require__(760); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } - - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; - - -/***/ }), -/* 871 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var regex = __webpack_require__(740); -var Cache = __webpack_require__(850); - -/** - * Utils - */ - -var utils = module.exports; -var cache = utils.cache = new Cache(); - -/** - * Cast `val` to an array - * @return {Array} - */ - -utils.arrayify = function(val) { - if (!Array.isArray(val)) { - return [val]; - } - return val; -}; - -/** - * Memoize a generated regex or function - */ - -utils.memoize = function(type, pattern, options, fn) { - var key = utils.createKey(type + pattern, options); - - if (cache.has(type, key)) { - return cache.get(type, key); - } - - var val = fn(pattern, options); - if (options && options.cache === false) { - return val; - } - - cache.set(type, key, val); - return val; -}; - -/** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ - -utils.createKey = function(pattern, options) { - var key = pattern; - if (typeof options === 'undefined') { - return key; - } - for (var prop in options) { - key += ';' + prop + '=' + String(options[prop]); - } - return key; -}; - -/** - * Create the regex to use for matching text - */ - -utils.createRegex = function(str) { - var opts = {contains: true, strictClose: false}; - return regex(str, opts); -}; - - -/***/ }), -/* 872 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Module dependencies - */ - -var Snapdragon = __webpack_require__(768); -var define = __webpack_require__(870); -var extend = __webpack_require__(738); - -/** - * Local dependencies - */ - -var compilers = __webpack_require__(858); -var parsers = __webpack_require__(869); - -/** - * Customize Snapdragon parser and renderer - */ - -function Extglob(options) { - this.options = extend({source: 'extglob'}, options); - this.snapdragon = this.options.snapdragon || new Snapdragon(this.options); - this.snapdragon.patterns = this.snapdragon.patterns || {}; - this.compiler = this.snapdragon.compiler; - this.parser = this.snapdragon.parser; - - compilers(this.snapdragon); - parsers(this.snapdragon); - - /** - * Override Snapdragon `.parse` method - */ - - define(this.snapdragon, 'parse', function(str, options) { - var parsed = Snapdragon.prototype.parse.apply(this, arguments); - parsed.input = str; - - // escape unmatched brace/bracket/parens - var last = this.parser.stack.pop(); - if (last && this.options.strict !== true) { - var node = last.nodes[0]; - node.val = '\\' + node.val; - var sibling = node.parent.nodes[1]; - if (sibling.type === 'star') { - sibling.loose = true; - } - } - - // add non-enumerable parser reference - define(parsed, 'parser', this.parser); - return parsed; - }); - - /** - * Decorate `.parse` method - */ - - define(this, 'parse', function(ast, options) { - return this.snapdragon.parse.apply(this.snapdragon, arguments); - }); - - /** - * Decorate `.compile` method - */ - - define(this, 'compile', function(ast, options) { - return this.snapdragon.compile.apply(this.snapdragon, arguments); - }); - -} - -/** - * Expose `Extglob` - */ - -module.exports = Extglob; - - -/***/ }), -/* 873 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var extglob = __webpack_require__(857); -var nanomatch = __webpack_require__(842); -var regexNot = __webpack_require__(740); -var toRegex = __webpack_require__(830); -var not; - -/** - * Characters to use in negation regex (we want to "not" match - * characters that are matched by other parsers) - */ - -var TEXT = '([!@*?+]?\\(|\\)|\\[:?(?=.*?:?\\])|:?\\]|[*+?!^$.\\\\/])+'; -var createNotRegex = function(opts) { - return not || (not = textRegex(TEXT)); -}; - -/** - * Parsers - */ - -module.exports = function(snapdragon) { - var parsers = snapdragon.parser.parsers; - - // register nanomatch parsers - snapdragon.use(nanomatch.parsers); - - // get references to some specific nanomatch parsers before they - // are overridden by the extglob and/or parsers - var escape = parsers.escape; - var slash = parsers.slash; - var qmark = parsers.qmark; - var plus = parsers.plus; - var star = parsers.star; - var dot = parsers.dot; - - // register extglob parsers - snapdragon.use(extglob.parsers); - - // custom micromatch parsers - snapdragon.parser - .use(function() { - // override "notRegex" created in nanomatch parser - this.notRegex = /^\!+(?!\()/; - }) - // reset the referenced parsers - .capture('escape', escape) - .capture('slash', slash) - .capture('qmark', qmark) - .capture('star', star) - .capture('plus', plus) - .capture('dot', dot) - - /** - * Override `text` parser - */ - - .capture('text', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(createNotRegex(this.options)); - if (!m || !m[0]) return; - - // escape regex boundary characters and simple brackets - var val = m[0].replace(/([[\]^$])/g, '\\$1'); - - return pos({ - type: 'text', - val: val - }); - }); -}; - -/** - * Create text regex - */ - -function textRegex(pattern) { - var notStr = regexNot.create(pattern, {contains: true, strictClose: false}); - var prefix = '(?:[\\^]|\\\\|'; - return toRegex(prefix + notStr + ')', {strictClose: false}); -} - - -/***/ }), -/* 874 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = new (__webpack_require__(850))(); - - -/***/ }), -/* 875 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = module.exports; -var path = __webpack_require__(16); - -/** - * Module dependencies - */ - -var Snapdragon = __webpack_require__(768); -utils.define = __webpack_require__(837); -utils.diff = __webpack_require__(854); -utils.extend = __webpack_require__(838); -utils.pick = __webpack_require__(855); -utils.typeOf = __webpack_require__(876); -utils.unique = __webpack_require__(741); - -/** - * Returns true if the platform is windows, or `path.sep` is `\\`. - * This is defined as a function to allow `path.sep` to be set in unit tests, - * or by the user, if there is a reason to do so. - * @return {Boolean} - */ - -utils.isWindows = function() { - return path.sep === '\\' || process.platform === 'win32'; -}; - -/** - * Get the `Snapdragon` instance to use - */ - -utils.instantiate = function(ast, options) { - var snapdragon; - // if an instance was created by `.parse`, use that instance - if (utils.typeOf(ast) === 'object' && ast.snapdragon) { - snapdragon = ast.snapdragon; - // if the user supplies an instance on options, use that instance - } else if (utils.typeOf(options) === 'object' && options.snapdragon) { - snapdragon = options.snapdragon; - // create a new instance - } else { - snapdragon = new Snapdragon(options); - } - - utils.define(snapdragon, 'parse', function(str, options) { - var parsed = Snapdragon.prototype.parse.apply(this, arguments); - parsed.input = str; - - // escape unmatched brace/bracket/parens - var last = this.parser.stack.pop(); - if (last && this.options.strictErrors !== true) { - var open = last.nodes[0]; - var inner = last.nodes[1]; - if (last.type === 'bracket') { - if (inner.val.charAt(0) === '[') { - inner.val = '\\' + inner.val; - } - - } else { - open.val = '\\' + open.val; - var sibling = open.parent.nodes[1]; - if (sibling.type === 'star') { - sibling.loose = true; - } - } - } - - // add non-enumerable parser reference - utils.define(parsed, 'parser', this.parser); - return parsed; - }); - - return snapdragon; -}; - -/** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ - -utils.createKey = function(pattern, options) { - if (utils.typeOf(options) !== 'object') { - return pattern; - } - var val = pattern; - var keys = Object.keys(options); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - val += ';' + key + '=' + String(options[key]); - } - return val; -}; - -/** - * Cast `val` to an array - * @return {Array} - */ - -utils.arrayify = function(val) { - if (typeof val === 'string') return [val]; - return val ? (Array.isArray(val) ? val : [val]) : []; -}; - -/** - * Return true if `val` is a non-empty string - */ - -utils.isString = function(val) { - return typeof val === 'string'; -}; - -/** - * Return true if `val` is a non-empty string - */ - -utils.isObject = function(val) { - return utils.typeOf(val) === 'object'; -}; - -/** - * Returns true if the given `str` has special characters - */ - -utils.hasSpecialChars = function(str) { - return /(?:(?:(^|\/)[!.])|[*?+()|\[\]{}]|[+@]\()/.test(str); -}; - -/** - * Escape regex characters in the given string - */ - -utils.escapeRegex = function(str) { - return str.replace(/[-[\]{}()^$|*+?.\\\/\s]/g, '\\$&'); -}; - -/** - * Normalize slashes in the given filepath. - * - * @param {String} `filepath` - * @return {String} - */ - -utils.toPosixPath = function(str) { - return str.replace(/\\+/g, '/'); -}; - -/** - * Strip backslashes before special characters in a string. - * - * @param {String} `str` - * @return {String} - */ - -utils.unescape = function(str) { - return utils.toPosixPath(str.replace(/\\(?=[*+?!.])/g, '')); -}; - -/** - * Strip the prefix from a filepath - * @param {String} `fp` - * @return {String} - */ - -utils.stripPrefix = function(str) { - if (str.charAt(0) !== '.') { - return str; - } - var ch = str.charAt(1); - if (utils.isSlash(ch)) { - return str.slice(2); - } - return str; -}; - -/** - * Returns true if the given str is an escaped or - * unescaped path character - */ - -utils.isSlash = function(str) { - return str === '/' || str === '\\/' || str === '\\' || str === '\\\\'; -}; - -/** - * Returns a function that returns true if the given - * pattern matches or contains a `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ - -utils.matchPath = function(pattern, options) { - return (options && options.contains) - ? utils.containsPattern(pattern, options) - : utils.equalsPattern(pattern, options); -}; - -/** - * Returns true if the given (original) filepath or unixified path are equal - * to the given pattern. - */ - -utils._equals = function(filepath, unixPath, pattern) { - return pattern === filepath || pattern === unixPath; -}; - -/** - * Returns true if the given (original) filepath or unixified path contain - * the given pattern. - */ - -utils._contains = function(filepath, unixPath, pattern) { - return filepath.indexOf(pattern) !== -1 || unixPath.indexOf(pattern) !== -1; -}; - -/** - * Returns a function that returns true if the given - * pattern is the same as a given `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ - -utils.equalsPattern = function(pattern, options) { - var unixify = utils.unixify(options); - options = options || {}; - - return function fn(filepath) { - var equal = utils._equals(filepath, unixify(filepath), pattern); - if (equal === true || options.nocase !== true) { - return equal; - } - var lower = filepath.toLowerCase(); - return utils._equals(lower, unixify(lower), pattern); - }; -}; - -/** - * Returns a function that returns true if the given - * pattern contains a `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ - -utils.containsPattern = function(pattern, options) { - var unixify = utils.unixify(options); - options = options || {}; - - return function(filepath) { - var contains = utils._contains(filepath, unixify(filepath), pattern); - if (contains === true || options.nocase !== true) { - return contains; - } - var lower = filepath.toLowerCase(); - return utils._contains(lower, unixify(lower), pattern); - }; -}; - -/** - * Returns a function that returns true if the given - * regex matches the `filename` of a file path. - * - * @param {RegExp} `re` Matching regex - * @return {Function} - */ - -utils.matchBasename = function(re) { - return function(filepath) { - return re.test(path.basename(filepath)); - }; -}; - -/** - * Determines the filepath to return based on the provided options. - * @return {any} - */ - -utils.value = function(str, unixify, options) { - if (options && options.unixify === false) { - return str; - } - return unixify(str); -}; - -/** - * Returns a function that normalizes slashes in a string to forward - * slashes, strips `./` from beginning of paths, and optionally unescapes - * special characters. - * @return {Function} - */ - -utils.unixify = function(options) { - options = options || {}; - return function(filepath) { - if (utils.isWindows() || options.unixify === true) { - filepath = utils.toPosixPath(filepath); - } - if (options.stripPrefix !== false) { - filepath = utils.stripPrefix(filepath); - } - if (options.unescape === true) { - filepath = utils.unescape(filepath); - } - return filepath; - }; -}; - - -/***/ }), -/* 876 */ -/***/ (function(module, exports) { - -var toString = Object.prototype.toString; - -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; - - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; - } - - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; - - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; - - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; - - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; - - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; - - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; - } - - if (isGeneratorObj(val)) { - return 'generator'; - } - - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; - } - - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); -}; - -function ctorName(val) { - return typeof val.constructor === 'function' ? val.constructor.name : null; -} - -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} - -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} - -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; -} - -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; -} - -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; -} - -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} - -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; - } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; - } - } - return false; -} - -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ - -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); - } - return false; -} - - -/***/ }), -/* 877 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(878); -var reader_1 = __webpack_require__(891); -var fs_stream_1 = __webpack_require__(895); -var ReaderAsync = /** @class */ (function (_super) { - __extends(ReaderAsync, _super); - function ReaderAsync() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(ReaderAsync.prototype, "fsAdapter", { - /** - * Returns FileSystem adapter. - */ - get: function () { - return new fs_stream_1.default(this.options); - }, - enumerable: true, - configurable: true - }); - /** - * Use async API to read entries for Task. - */ - ReaderAsync.prototype.read = function (task) { - var _this = this; - var root = this.getRootDirectory(task); - var options = this.getReaderOptions(task); - var entries = []; - return new Promise(function (resolve, reject) { - var stream = _this.api(root, task, options); - stream.on('error', function (err) { - _this.isEnoentCodeError(err) ? resolve([]) : reject(err); - stream.pause(); - }); - stream.on('data', function (entry) { return entries.push(_this.transform(entry)); }); - stream.on('end', function () { return resolve(entries); }); - }); - }; - /** - * Returns founded paths. - */ - ReaderAsync.prototype.api = function (root, task, options) { - if (task.dynamic) { - return this.dynamicApi(root, options); - } - return this.staticApi(task, options); - }; - /** - * Api for dynamic tasks. - */ - ReaderAsync.prototype.dynamicApi = function (root, options) { - return readdir.readdirStreamStat(root, options); - }; - /** - * Api for static tasks. - */ - ReaderAsync.prototype.staticApi = function (task, options) { - return this.fsAdapter.read(task.patterns, options.filter); - }; - return ReaderAsync; -}(reader_1.default)); -exports.default = ReaderAsync; - - -/***/ }), -/* 878 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const readdirSync = __webpack_require__(879); -const readdirAsync = __webpack_require__(887); -const readdirStream = __webpack_require__(890); - -module.exports = exports = readdirAsyncPath; -exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; -exports.readdirAsyncStat = exports.async.stat = readdirAsyncStat; -exports.readdirStream = exports.stream = readdirStreamPath; -exports.readdirStreamStat = exports.stream.stat = readdirStreamStat; -exports.readdirSync = exports.sync = readdirSyncPath; -exports.readdirSyncStat = exports.sync.stat = readdirSyncStat; - -/** - * Synchronous readdir that returns an array of string paths. - * - * @param {string} dir - * @param {object} [options] - * @returns {string[]} - */ -function readdirSyncPath (dir, options) { - return readdirSync(dir, options, {}); -} - -/** - * Synchronous readdir that returns results as an array of {@link fs.Stats} objects - * - * @param {string} dir - * @param {object} [options] - * @returns {fs.Stats[]} - */ -function readdirSyncStat (dir, options) { - return readdirSync(dir, options, { stats: true }); -} - -/** - * Aynchronous readdir (accepts an error-first callback or returns a {@link Promise}). - * Results are an array of path strings. - * - * @param {string} dir - * @param {object} [options] - * @param {function} [callback] - * @returns {Promise} - */ -function readdirAsyncPath (dir, options, callback) { - return readdirAsync(dir, options, callback, {}); -} - -/** - * Aynchronous readdir (accepts an error-first callback or returns a {@link Promise}). - * Results are an array of {@link fs.Stats} objects. - * - * @param {string} dir - * @param {object} [options] - * @param {function} [callback] - * @returns {Promise} - */ -function readdirAsyncStat (dir, options, callback) { - return readdirAsync(dir, options, callback, { stats: true }); -} - -/** - * Aynchronous readdir that returns a {@link stream.Readable} (which is also an {@link EventEmitter}). - * All stream data events ("data", "file", "directory", "symlink") are passed a path string. - * - * @param {string} dir - * @param {object} [options] - * @returns {stream.Readable} - */ -function readdirStreamPath (dir, options) { - return readdirStream(dir, options, {}); -} - -/** - * Aynchronous readdir that returns a {@link stream.Readable} (which is also an {@link EventEmitter}) - * All stream data events ("data", "file", "directory", "symlink") are passed an {@link fs.Stats} object. - * - * @param {string} dir - * @param {object} [options] - * @returns {stream.Readable} - */ -function readdirStreamStat (dir, options) { - return readdirStream(dir, options, { stats: true }); -} - - -/***/ }), -/* 879 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = readdirSync; - -const DirectoryReader = __webpack_require__(880); - -let syncFacade = { - fs: __webpack_require__(885), - forEach: __webpack_require__(886), - sync: true -}; - -/** - * Returns the buffered output from a synchronous {@link DirectoryReader}. - * - * @param {string} dir - * @param {object} [options] - * @param {object} internalOptions - */ -function readdirSync (dir, options, internalOptions) { - internalOptions.facade = syncFacade; - - let reader = new DirectoryReader(dir, options, internalOptions); - let stream = reader.stream; - - let results = []; - let data = stream.read(); - while (data !== null) { - results.push(data); - data = stream.read(); - } - - return results; -} - - -/***/ }), -/* 880 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const Readable = __webpack_require__(27).Readable; -const EventEmitter = __webpack_require__(379).EventEmitter; -const path = __webpack_require__(16); -const normalizeOptions = __webpack_require__(881); -const stat = __webpack_require__(883); -const call = __webpack_require__(884); - -/** - * Asynchronously reads the contents of a directory and streams the results - * via a {@link stream.Readable}. - */ -class DirectoryReader { - /** - * @param {string} dir - The absolute or relative directory path to read - * @param {object} [options] - User-specified options, if any (see {@link normalizeOptions}) - * @param {object} internalOptions - Internal options that aren't part of the public API - * @class - */ - constructor (dir, options, internalOptions) { - this.options = options = normalizeOptions(options, internalOptions); - - // Indicates whether we should keep reading - // This is set false if stream.Readable.push() returns false. - this.shouldRead = true; - - // The directories to read - // (initialized with the top-level directory) - this.queue = [{ - path: dir, - basePath: options.basePath, - posixBasePath: options.posixBasePath, - depth: 0 - }]; - - // The number of directories that are currently being processed - this.pending = 0; - - // The data that has been read, but not yet emitted - this.buffer = []; - - this.stream = new Readable({ objectMode: true }); - this.stream._read = () => { - // Start (or resume) reading - this.shouldRead = true; - - // If we have data in the buffer, then send the next chunk - if (this.buffer.length > 0) { - this.pushFromBuffer(); - } - - // If we have directories queued, then start processing the next one - if (this.queue.length > 0) { - if (this.options.facade.sync) { - while (this.queue.length > 0) { - this.readNextDirectory(); - } - } - else { - this.readNextDirectory(); - } - } - - this.checkForEOF(); - }; - } - - /** - * Reads the next directory in the queue - */ - readNextDirectory () { - let facade = this.options.facade; - let dir = this.queue.shift(); - this.pending++; - - // Read the directory listing - call.safe(facade.fs.readdir, dir.path, (err, items) => { - if (err) { - // fs.readdir threw an error - this.emit('error', err); - return this.finishedReadingDirectory(); - } - - try { - // Process each item in the directory (simultaneously, if async) - facade.forEach( - items, - this.processItem.bind(this, dir), - this.finishedReadingDirectory.bind(this, dir) - ); - } - catch (err2) { - // facade.forEach threw an error - // (probably because fs.readdir returned an invalid result) - this.emit('error', err2); - this.finishedReadingDirectory(); - } - }); - } - - /** - * This method is called after all items in a directory have been processed. - * - * NOTE: This does not necessarily mean that the reader is finished, since there may still - * be other directories queued or pending. - */ - finishedReadingDirectory () { - this.pending--; - - if (this.shouldRead) { - // If we have directories queued, then start processing the next one - if (this.queue.length > 0 && this.options.facade.async) { - this.readNextDirectory(); - } - - this.checkForEOF(); - } - } - - /** - * Determines whether the reader has finished processing all items in all directories. - * If so, then the "end" event is fired (via {@Readable#push}) - */ - checkForEOF () { - if (this.buffer.length === 0 && // The stuff we've already read - this.pending === 0 && // The stuff we're currently reading - this.queue.length === 0) { // The stuff we haven't read yet - // There's no more stuff! - this.stream.push(null); - } - } - - /** - * Processes a single item in a directory. - * - * If the item is a directory, and `option.deep` is enabled, then the item will be added - * to the directory queue. - * - * If the item meets the filter criteria, then it will be emitted to the reader's stream. - * - * @param {object} dir - A directory object from the queue - * @param {string} item - The name of the item (name only, no path) - * @param {function} done - A callback function that is called after the item has been processed - */ - processItem (dir, item, done) { - let stream = this.stream; - let options = this.options; - - let itemPath = dir.basePath + item; - let posixPath = dir.posixBasePath + item; - let fullPath = path.join(dir.path, item); - - // If `options.deep` is a number, and we've already recursed to the max depth, - // then there's no need to check fs.Stats to know if it's a directory. - // If `options.deep` is a function, then we'll need fs.Stats - let maxDepthReached = dir.depth >= options.recurseDepth; - - // Do we need to call `fs.stat`? - let needStats = - !maxDepthReached || // we need the fs.Stats to know if it's a directory - options.stats || // the user wants fs.Stats objects returned - options.recurseFn || // we need fs.Stats for the recurse function - options.filterFn || // we need fs.Stats for the filter function - EventEmitter.listenerCount(stream, 'file') || // we need the fs.Stats to know if it's a file - EventEmitter.listenerCount(stream, 'directory') || // we need the fs.Stats to know if it's a directory - EventEmitter.listenerCount(stream, 'symlink'); // we need the fs.Stats to know if it's a symlink - - // If we don't need stats, then exit early - if (!needStats) { - if (this.filter(itemPath, posixPath)) { - this.pushOrBuffer({ data: itemPath }); - } - return done(); - } - - // Get the fs.Stats object for this path - stat(options.facade.fs, fullPath, (err, stats) => { - if (err) { - // fs.stat threw an error - this.emit('error', err); - return done(); - } - - try { - // Add the item's path to the fs.Stats object - // The base of this path, and its separators are determined by the options - // (i.e. options.basePath and options.sep) - stats.path = itemPath; - - // Add depth of the path to the fs.Stats object for use this in the filter function - stats.depth = dir.depth; - - if (this.shouldRecurse(stats, posixPath, maxDepthReached)) { - // Add this subdirectory to the queue - this.queue.push({ - path: fullPath, - basePath: itemPath + options.sep, - posixBasePath: posixPath + '/', - depth: dir.depth + 1, - }); - } - - // Determine whether this item matches the filter criteria - if (this.filter(stats, posixPath)) { - this.pushOrBuffer({ - data: options.stats ? stats : itemPath, - file: stats.isFile(), - directory: stats.isDirectory(), - symlink: stats.isSymbolicLink(), - }); - } - - done(); - } - catch (err2) { - // An error occurred while processing the item - // (probably during a user-specified function, such as options.deep, options.filter, etc.) - this.emit('error', err2); - done(); - } - }); - } - - /** - * Pushes the given chunk of data to the stream, or adds it to the buffer, - * depending on the state of the stream. - * - * @param {object} chunk - */ - pushOrBuffer (chunk) { - // Add the chunk to the buffer - this.buffer.push(chunk); - - // If we're still reading, then immediately emit the next chunk in the buffer - // (which may or may not be the chunk that we just added) - if (this.shouldRead) { - this.pushFromBuffer(); - } - } - - /** - * Immediately pushes the next chunk in the buffer to the reader's stream. - * The "data" event will always be fired (via {@link Readable#push}). - * In addition, the "file", "directory", and/or "symlink" events may be fired, - * depending on the type of properties of the chunk. - */ - pushFromBuffer () { - let stream = this.stream; - let chunk = this.buffer.shift(); - - // Stream the data - try { - this.shouldRead = stream.push(chunk.data); - } - catch (err) { - this.emit('error', err); - } - - // Also emit specific events, based on the type of chunk - chunk.file && this.emit('file', chunk.data); - chunk.symlink && this.emit('symlink', chunk.data); - chunk.directory && this.emit('directory', chunk.data); - } - - /** - * Determines whether the given directory meets the user-specified recursion criteria. - * If the user didn't specify recursion criteria, then this function will default to true. - * - * @param {fs.Stats} stats - The directory's {@link fs.Stats} object - * @param {string} posixPath - The item's POSIX path (used for glob matching) - * @param {boolean} maxDepthReached - Whether we've already crawled the user-specified depth - * @returns {boolean} - */ - shouldRecurse (stats, posixPath, maxDepthReached) { - let options = this.options; - - if (maxDepthReached) { - // We've already crawled to the maximum depth. So no more recursion. - return false; - } - else if (!stats.isDirectory()) { - // It's not a directory. So don't try to crawl it. - return false; - } - else if (options.recurseGlob) { - // Glob patterns are always tested against the POSIX path, even on Windows - // https://github.com/isaacs/node-glob#windows - return options.recurseGlob.test(posixPath); - } - else if (options.recurseRegExp) { - // Regular expressions are tested against the normal path - // (based on the OS or options.sep) - return options.recurseRegExp.test(stats.path); - } - else if (options.recurseFn) { - try { - // Run the user-specified recursion criteria - return options.recurseFn.call(null, stats); - } - catch (err) { - // An error occurred in the user's code. - // In Sync and Async modes, this will return an error. - // In Streaming mode, we emit an "error" event, but continue processing - this.emit('error', err); - } - } - else { - // No recursion function was specified, and we're within the maximum depth. - // So crawl this directory. - return true; - } - } - - /** - * Determines whether the given item meets the user-specified filter criteria. - * If the user didn't specify a filter, then this function will always return true. - * - * @param {string|fs.Stats} value - Either the item's path, or the item's {@link fs.Stats} object - * @param {string} posixPath - The item's POSIX path (used for glob matching) - * @returns {boolean} - */ - filter (value, posixPath) { - let options = this.options; - - if (options.filterGlob) { - // Glob patterns are always tested against the POSIX path, even on Windows - // https://github.com/isaacs/node-glob#windows - return options.filterGlob.test(posixPath); - } - else if (options.filterRegExp) { - // Regular expressions are tested against the normal path - // (based on the OS or options.sep) - return options.filterRegExp.test(value.path || value); - } - else if (options.filterFn) { - try { - // Run the user-specified filter function - return options.filterFn.call(null, value); - } - catch (err) { - // An error occurred in the user's code. - // In Sync and Async modes, this will return an error. - // In Streaming mode, we emit an "error" event, but continue processing - this.emit('error', err); - } - } - else { - // No filter was specified, so match everything - return true; - } - } - - /** - * Emits an event. If one of the event listeners throws an error, - * then an "error" event is emitted. - * - * @param {string} eventName - * @param {*} data - */ - emit (eventName, data) { - let stream = this.stream; - - try { - stream.emit(eventName, data); - } - catch (err) { - if (eventName === 'error') { - // Don't recursively emit "error" events. - // If the first one fails, then just throw - throw err; - } - else { - stream.emit('error', err); - } - } - } -} - -module.exports = DirectoryReader; - - -/***/ }), -/* 881 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const path = __webpack_require__(16); -const globToRegExp = __webpack_require__(882); - -module.exports = normalizeOptions; - -let isWindows = /^win/.test(process.platform); - -/** - * @typedef {Object} FSFacade - * @property {fs.readdir} readdir - * @property {fs.stat} stat - * @property {fs.lstat} lstat - */ - -/** - * Validates and normalizes the options argument - * - * @param {object} [options] - User-specified options, if any - * @param {object} internalOptions - Internal options that aren't part of the public API - * - * @param {number|boolean|function} [options.deep] - * The number of directories to recursively traverse. Any falsy value or negative number will - * default to zero, so only the top-level contents will be returned. Set to `true` or `Infinity` - * to traverse all subdirectories. Or provide a function that accepts a {@link fs.Stats} object - * and returns a truthy value if the directory's contents should be crawled. - * - * @param {function|string|RegExp} [options.filter] - * A function that accepts a {@link fs.Stats} object and returns a truthy value if the data should - * be returned. Or a RegExp or glob string pattern, to filter by file name. - * - * @param {string} [options.sep] - * The path separator to use. By default, the OS-specific separator will be used, but this can be - * set to a specific value to ensure consistency across platforms. - * - * @param {string} [options.basePath] - * The base path to prepend to each result. If empty, then all results will be relative to `dir`. - * - * @param {FSFacade} [options.fs] - * Synchronous or asynchronous facades for Node.js File System module - * - * @param {object} [internalOptions.facade] - * Synchronous or asynchronous facades for various methods, including for the Node.js File System module - * - * @param {boolean} [internalOptions.emit] - * Indicates whether the reader should emit "file", "directory", and "symlink" events - * - * @param {boolean} [internalOptions.stats] - * Indicates whether the reader should emit {@link fs.Stats} objects instead of path strings - * - * @returns {object} - */ -function normalizeOptions (options, internalOptions) { - if (options === null || options === undefined) { - options = {}; - } - else if (typeof options !== 'object') { - throw new TypeError('options must be an object'); - } - - let recurseDepth, recurseFn, recurseRegExp, recurseGlob, deep = options.deep; - if (deep === null || deep === undefined) { - recurseDepth = 0; - } - else if (typeof deep === 'boolean') { - recurseDepth = deep ? Infinity : 0; - } - else if (typeof deep === 'number') { - if (deep < 0 || isNaN(deep)) { - throw new Error('options.deep must be a positive number'); - } - else if (Math.floor(deep) !== deep) { - throw new Error('options.deep must be an integer'); - } - else { - recurseDepth = deep; - } - } - else if (typeof deep === 'function') { - recurseDepth = Infinity; - recurseFn = deep; - } - else if (deep instanceof RegExp) { - recurseDepth = Infinity; - recurseRegExp = deep; - } - else if (typeof deep === 'string' && deep.length > 0) { - recurseDepth = Infinity; - recurseGlob = globToRegExp(deep, { extended: true, globstar: true }); - } - else { - throw new TypeError('options.deep must be a boolean, number, function, regular expression, or glob pattern'); - } - - let filterFn, filterRegExp, filterGlob, filter = options.filter; - if (filter !== null && filter !== undefined) { - if (typeof filter === 'function') { - filterFn = filter; - } - else if (filter instanceof RegExp) { - filterRegExp = filter; - } - else if (typeof filter === 'string' && filter.length > 0) { - filterGlob = globToRegExp(filter, { extended: true, globstar: true }); - } - else { - throw new TypeError('options.filter must be a function, regular expression, or glob pattern'); - } - } - - let sep = options.sep; - if (sep === null || sep === undefined) { - sep = path.sep; - } - else if (typeof sep !== 'string') { - throw new TypeError('options.sep must be a string'); - } - - let basePath = options.basePath; - if (basePath === null || basePath === undefined) { - basePath = ''; - } - else if (typeof basePath === 'string') { - // Append a path separator to the basePath, if necessary - if (basePath && basePath.substr(-1) !== sep) { - basePath += sep; - } - } - else { - throw new TypeError('options.basePath must be a string'); - } - - // Convert the basePath to POSIX (forward slashes) - // so that glob pattern matching works consistently, even on Windows - let posixBasePath = basePath; - if (posixBasePath && sep !== '/') { - posixBasePath = posixBasePath.replace(new RegExp('\\' + sep, 'g'), '/'); - - /* istanbul ignore if */ - if (isWindows) { - // Convert Windows root paths (C:\) and UNCs (\\) to POSIX root paths - posixBasePath = posixBasePath.replace(/^([a-zA-Z]\:\/|\/\/)/, '/'); - } - } - - // Determine which facade methods to use - let facade; - if (options.fs === null || options.fs === undefined) { - // The user didn't provide their own facades, so use our internal ones - facade = internalOptions.facade; - } - else if (typeof options.fs === 'object') { - // Merge the internal facade methods with the user-provided `fs` facades - facade = Object.assign({}, internalOptions.facade); - facade.fs = Object.assign({}, internalOptions.facade.fs, options.fs); - } - else { - throw new TypeError('options.fs must be an object'); - } - - return { - recurseDepth, - recurseFn, - recurseRegExp, - recurseGlob, - filterFn, - filterRegExp, - filterGlob, - sep, - basePath, - posixBasePath, - facade, - emit: !!internalOptions.emit, - stats: !!internalOptions.stats, - }; -} - - -/***/ }), -/* 882 */ -/***/ (function(module, exports) { - -module.exports = function (glob, opts) { - if (typeof glob !== 'string') { - throw new TypeError('Expected a string'); - } - - var str = String(glob); - - // The regexp we are building, as a string. - var reStr = ""; - - // Whether we are matching so called "extended" globs (like bash) and should - // support single character matching, matching ranges of characters, group - // matching, etc. - var extended = opts ? !!opts.extended : false; - - // When globstar is _false_ (default), '/foo/*' is translated a regexp like - // '^\/foo\/.*$' which will match any string beginning with '/foo/' - // When globstar is _true_, '/foo/*' is translated to regexp like - // '^\/foo\/[^/]*$' which will match any string beginning with '/foo/' BUT - // which does not have a '/' to the right of it. - // E.g. with '/foo/*' these will match: '/foo/bar', '/foo/bar.txt' but - // these will not '/foo/bar/baz', '/foo/bar/baz.txt' - // Lastely, when globstar is _true_, '/foo/**' is equivelant to '/foo/*' when - // globstar is _false_ - var globstar = opts ? !!opts.globstar : false; - - // If we are doing extended matching, this boolean is true when we are inside - // a group (eg {*.html,*.js}), and false otherwise. - var inGroup = false; - - // RegExp flags (eg "i" ) to pass in to RegExp constructor. - var flags = opts && typeof( opts.flags ) === "string" ? opts.flags : ""; - - var c; - for (var i = 0, len = str.length; i < len; i++) { - c = str[i]; - - switch (c) { - case "\\": - case "/": - case "$": - case "^": - case "+": - case ".": - case "(": - case ")": - case "=": - case "!": - case "|": - reStr += "\\" + c; - break; - - case "?": - if (extended) { - reStr += "."; - break; - } - - case "[": - case "]": - if (extended) { - reStr += c; - break; - } - - case "{": - if (extended) { - inGroup = true; - reStr += "("; - break; - } - - case "}": - if (extended) { - inGroup = false; - reStr += ")"; - break; - } - - case ",": - if (inGroup) { - reStr += "|"; - break; - } - reStr += "\\" + c; - break; - - case "*": - // Move over all consecutive "*"'s. - // Also store the previous and next characters - var prevChar = str[i - 1]; - var starCount = 1; - while(str[i + 1] === "*") { - starCount++; - i++; - } - var nextChar = str[i + 1]; - - if (!globstar) { - // globstar is disabled, so treat any number of "*" as one - reStr += ".*"; - } else { - // globstar is enabled, so determine if this is a globstar segment - var isGlobstar = starCount > 1 // multiple "*"'s - && (prevChar === "/" || prevChar === undefined) // from the start of the segment - && (nextChar === "/" || nextChar === undefined) // to the end of the segment - - if (isGlobstar) { - // it's a globstar, so match zero or more path segments - reStr += "(?:[^/]*(?:\/|$))*"; - i++; // move over the "/" - } else { - // it's not a globstar, so only match one path segment - reStr += "[^/]*"; - } - } - break; - - default: - reStr += c; - } - } - - // When regexp 'g' flag is specified don't - // constrain the regular expression with ^ & $ - if (!flags || !~flags.indexOf('g')) { - reStr = "^" + reStr + "$"; - } - - return new RegExp(reStr, flags); -}; - - -/***/ }), -/* 883 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const call = __webpack_require__(884); - -module.exports = stat; - -/** - * Retrieves the {@link fs.Stats} for the given path. If the path is a symbolic link, - * then the Stats of the symlink's target are returned instead. If the symlink is broken, - * then the Stats of the symlink itself are returned. - * - * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module - * @param {string} path - The path to return stats for - * @param {function} callback - */ -function stat (fs, path, callback) { - let isSymLink = false; - - call.safe(fs.lstat, path, (err, lstats) => { - if (err) { - // fs.lstat threw an eror - return callback(err); - } - - try { - isSymLink = lstats.isSymbolicLink(); - } - catch (err2) { - // lstats.isSymbolicLink() threw an error - // (probably because fs.lstat returned an invalid result) - return callback(err2); - } - - if (isSymLink) { - // Try to resolve the symlink - symlinkStat(fs, path, lstats, callback); - } - else { - // It's not a symlink, so return the stats as-is - callback(null, lstats); - } - }); -} - -/** - * Retrieves the {@link fs.Stats} for the target of the given symlink. - * If the symlink is broken, then the Stats of the symlink itself are returned. - * - * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module - * @param {string} path - The path of the symlink to return stats for - * @param {object} lstats - The stats of the symlink - * @param {function} callback - */ -function symlinkStat (fs, path, lstats, callback) { - call.safe(fs.stat, path, (err, stats) => { - if (err) { - // The symlink is broken, so return the stats for the link itself - return callback(null, lstats); - } - - try { - // Return the stats for the resolved symlink target, - // and override the `isSymbolicLink` method to indicate that it's a symlink - stats.isSymbolicLink = () => true; - } - catch (err2) { - // Setting stats.isSymbolicLink threw an error - // (probably because fs.stat returned an invalid result) - return callback(err2); - } - - callback(null, stats); - }); -} - - -/***/ }), -/* 884 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -let call = module.exports = { - safe: safeCall, - once: callOnce, -}; - -/** - * Calls a function with the given arguments, and ensures that the error-first callback is _always_ - * invoked exactly once, even if the function throws an error. - * - * @param {function} fn - The function to invoke - * @param {...*} args - The arguments to pass to the function. The final argument must be a callback function. - */ -function safeCall (fn, args) { - // Get the function arguments as an array - args = Array.prototype.slice.call(arguments, 1); - - // Replace the callback function with a wrapper that ensures it will only be called once - let callback = call.once(args.pop()); - args.push(callback); - - try { - fn.apply(null, args); - } - catch (err) { - callback(err); - } -} - -/** - * Returns a wrapper function that ensures the given callback function is only called once. - * Subsequent calls are ignored, unless the first argument is an Error, in which case the - * error is thrown. - * - * @param {function} fn - The function that should only be called once - * @returns {function} - */ -function callOnce (fn) { - let fulfilled = false; - - return function onceWrapper (err) { - if (!fulfilled) { - fulfilled = true; - return fn.apply(this, arguments); - } - else if (err) { - // The callback has already been called, but now an error has occurred - // (most likely inside the callback function). So re-throw the error, - // so it gets handled further up the call stack - throw err; - } - }; -} - - -/***/ }), -/* 885 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const fs = __webpack_require__(23); -const call = __webpack_require__(884); - -/** - * A facade around {@link fs.readdirSync} that allows it to be called - * the same way as {@link fs.readdir}. - * - * @param {string} dir - * @param {function} callback - */ -exports.readdir = function (dir, callback) { - // Make sure the callback is only called once - callback = call.once(callback); - - try { - let items = fs.readdirSync(dir); - callback(null, items); - } - catch (err) { - callback(err); - } -}; - -/** - * A facade around {@link fs.statSync} that allows it to be called - * the same way as {@link fs.stat}. - * - * @param {string} path - * @param {function} callback - */ -exports.stat = function (path, callback) { - // Make sure the callback is only called once - callback = call.once(callback); - - try { - let stats = fs.statSync(path); - callback(null, stats); - } - catch (err) { - callback(err); - } -}; - -/** - * A facade around {@link fs.lstatSync} that allows it to be called - * the same way as {@link fs.lstat}. - * - * @param {string} path - * @param {function} callback - */ -exports.lstat = function (path, callback) { - // Make sure the callback is only called once - callback = call.once(callback); - - try { - let stats = fs.lstatSync(path); - callback(null, stats); - } - catch (err) { - callback(err); - } -}; - - -/***/ }), -/* 886 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = syncForEach; - -/** - * A facade that allows {@link Array.forEach} to be called as though it were asynchronous. - * - * @param {array} array - The array to iterate over - * @param {function} iterator - The function to call for each item in the array - * @param {function} done - The function to call when all iterators have completed - */ -function syncForEach (array, iterator, done) { - array.forEach(item => { - iterator(item, () => { - // Note: No error-handling here because this is currently only ever called - // by DirectoryReader, which never passes an `error` parameter to the callback. - // Instead, DirectoryReader emits an "error" event if an error occurs. - }); - }); - - done(); -} - - -/***/ }), -/* 887 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = readdirAsync; - -const maybe = __webpack_require__(888); -const DirectoryReader = __webpack_require__(880); - -let asyncFacade = { - fs: __webpack_require__(23), - forEach: __webpack_require__(889), - async: true -}; - -/** - * Returns the buffered output from an asynchronous {@link DirectoryReader}, - * via an error-first callback or a {@link Promise}. - * - * @param {string} dir - * @param {object} [options] - * @param {function} [callback] - * @param {object} internalOptions - */ -function readdirAsync (dir, options, callback, internalOptions) { - if (typeof options === 'function') { - callback = options; - options = undefined; - } - - return maybe(callback, new Promise(((resolve, reject) => { - let results = []; - - internalOptions.facade = asyncFacade; - - let reader = new DirectoryReader(dir, options, internalOptions); - let stream = reader.stream; - - stream.on('error', err => { - reject(err); - stream.pause(); - }); - stream.on('data', result => { - results.push(result); - }); - stream.on('end', () => { - resolve(results); - }); - }))); -} - - -/***/ }), -/* 888 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var next = (global.process && process.nextTick) || global.setImmediate || function (f) { - setTimeout(f, 0) -} - -module.exports = function maybe (cb, promise) { - if (cb) { - promise - .then(function (result) { - next(function () { cb(null, result) }) - }, function (err) { - next(function () { cb(err) }) - }) - return undefined - } - else { - return promise - } -} - - -/***/ }), -/* 889 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = asyncForEach; - -/** - * Simultaneously processes all items in the given array. - * - * @param {array} array - The array to iterate over - * @param {function} iterator - The function to call for each item in the array - * @param {function} done - The function to call when all iterators have completed - */ -function asyncForEach (array, iterator, done) { - if (array.length === 0) { - // NOTE: Normally a bad idea to mix sync and async, but it's safe here because - // of the way that this method is currently used by DirectoryReader. - done(); - return; - } - - // Simultaneously process all items in the array. - let pending = array.length; - array.forEach(item => { - iterator(item, () => { - if (--pending === 0) { - done(); - } - }); - }); -} - - -/***/ }), -/* 890 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = readdirStream; - -const DirectoryReader = __webpack_require__(880); - -let streamFacade = { - fs: __webpack_require__(23), - forEach: __webpack_require__(889), - async: true -}; - -/** - * Returns the {@link stream.Readable} of an asynchronous {@link DirectoryReader}. - * - * @param {string} dir - * @param {object} [options] - * @param {object} internalOptions - */ -function readdirStream (dir, options, internalOptions) { - internalOptions.facade = streamFacade; - - let reader = new DirectoryReader(dir, options, internalOptions); - return reader.stream; -} - - -/***/ }), -/* 891 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(16); -var deep_1 = __webpack_require__(892); -var entry_1 = __webpack_require__(894); -var pathUtil = __webpack_require__(893); -var Reader = /** @class */ (function () { - function Reader(options) { - this.options = options; - this.micromatchOptions = this.getMicromatchOptions(); - this.entryFilter = new entry_1.default(options, this.micromatchOptions); - this.deepFilter = new deep_1.default(options, this.micromatchOptions); - } - /** - * Returns root path to scanner. - */ - Reader.prototype.getRootDirectory = function (task) { - return path.resolve(this.options.cwd, task.base); - }; - /** - * Returns options for reader. - */ - Reader.prototype.getReaderOptions = function (task) { - return { - basePath: task.base === '.' ? '' : task.base, - filter: this.entryFilter.getFilter(task.positive, task.negative), - deep: this.deepFilter.getFilter(task.positive, task.negative), - sep: '/' - }; - }; - /** - * Returns options for micromatch. - */ - Reader.prototype.getMicromatchOptions = function () { - return { - dot: this.options.dot, - nobrace: !this.options.brace, - noglobstar: !this.options.globstar, - noext: !this.options.extension, - nocase: !this.options.case, - matchBase: this.options.matchBase - }; - }; - /** - * Returns transformed entry. - */ - Reader.prototype.transform = function (entry) { - if (this.options.absolute) { - entry.path = pathUtil.makeAbsolute(this.options.cwd, entry.path); - } - if (this.options.markDirectories && entry.isDirectory()) { - entry.path += '/'; - } - var item = this.options.stats ? entry : entry.path; - if (this.options.transform === null) { - return item; - } - return this.options.transform(item); - }; - /** - * Returns true if error has ENOENT code. - */ - Reader.prototype.isEnoentCodeError = function (err) { - return err.code === 'ENOENT'; - }; - return Reader; -}()); -exports.default = Reader; - - -/***/ }), -/* 892 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(893); -var patternUtils = __webpack_require__(722); -var DeepFilter = /** @class */ (function () { - function DeepFilter(options, micromatchOptions) { - this.options = options; - this.micromatchOptions = micromatchOptions; - } - /** - * Returns filter for directories. - */ - DeepFilter.prototype.getFilter = function (positive, negative) { - var _this = this; - var maxPatternDepth = this.getMaxPatternDepth(positive); - var negativeRe = this.getNegativePatternsRe(negative); - return function (entry) { return _this.filter(entry, negativeRe, maxPatternDepth); }; - }; - /** - * Returns max depth of the provided patterns. - */ - DeepFilter.prototype.getMaxPatternDepth = function (patterns) { - var globstar = patterns.some(patternUtils.hasGlobStar); - return globstar ? Infinity : patternUtils.getMaxNaivePatternsDepth(patterns); - }; - /** - * Returns RegExp's for patterns that can affect the depth of reading. - */ - DeepFilter.prototype.getNegativePatternsRe = function (patterns) { - var affectDepthOfReadingPatterns = patterns.filter(patternUtils.isAffectDepthOfReadingPattern); - return patternUtils.convertPatternsToRe(affectDepthOfReadingPatterns, this.micromatchOptions); - }; - /** - * Returns «true» for directory that should be read. - */ - DeepFilter.prototype.filter = function (entry, negativeRe, maxPatternDepth) { - if (this.isSkippedByDeepOption(entry.depth)) { - return false; - } - if (this.isSkippedByMaxPatternDepth(entry.depth, maxPatternDepth)) { - return false; - } - if (this.isSkippedSymlinkedDirectory(entry)) { - return false; - } - if (this.isSkippedDotDirectory(entry)) { - return false; - } - return this.isSkippedByNegativePatterns(entry, negativeRe); - }; - /** - * Returns «true» when the «deep» option is disabled or number and depth of the entry is greater that the option value. - */ - DeepFilter.prototype.isSkippedByDeepOption = function (entryDepth) { - return !this.options.deep || (typeof this.options.deep === 'number' && entryDepth >= this.options.deep); - }; - /** - * Returns «true» when depth parameter is not an Infinity and entry depth greater that the parameter value. - */ - DeepFilter.prototype.isSkippedByMaxPatternDepth = function (entryDepth, maxPatternDepth) { - return maxPatternDepth !== Infinity && entryDepth >= maxPatternDepth; - }; - /** - * Returns «true» for symlinked directory if the «followSymlinkedDirectories» option is disabled. - */ - DeepFilter.prototype.isSkippedSymlinkedDirectory = function (entry) { - return !this.options.followSymlinkedDirectories && entry.isSymbolicLink(); - }; - /** - * Returns «true» for a directory whose name starts with a period if «dot» option is disabled. - */ - DeepFilter.prototype.isSkippedDotDirectory = function (entry) { - return !this.options.dot && pathUtils.isDotDirectory(entry.path); - }; - /** - * Returns «true» for a directory whose path math to any negative pattern. - */ - DeepFilter.prototype.isSkippedByNegativePatterns = function (entry, negativeRe) { - return !patternUtils.matchAny(entry.path, negativeRe); - }; - return DeepFilter; -}()); -exports.default = DeepFilter; + // if we know it exists, but not what it is. + } + var exists + var stat = this.statCache[abs] + if (!stat) { + var lstat + try { + lstat = fs.lstatSync(abs) + } catch (er) { + if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { + this.statCache[abs] = false + return false + } + } -/***/ }), -/* 893 */ -/***/ (function(module, exports, __webpack_require__) { + if (lstat && lstat.isSymbolicLink()) { + try { + stat = fs.statSync(abs) + } catch (er) { + stat = lstat + } + } else { + stat = lstat + } + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(16); -/** - * Returns «true» if the last partial of the path starting with a period. - */ -function isDotDirectory(filepath) { - return path.basename(filepath).startsWith('.'); -} -exports.isDotDirectory = isDotDirectory; -/** - * Convert a windows-like path to a unix-style path. - */ -function normalize(filepath) { - return filepath.replace(/\\/g, '/'); -} -exports.normalize = normalize; -/** - * Returns normalized absolute path of provided filepath. - */ -function makeAbsolute(cwd, filepath) { - return normalize(path.resolve(cwd, filepath)); -} -exports.makeAbsolute = makeAbsolute; + this.statCache[abs] = stat + var c = true + if (stat) + c = stat.isDirectory() ? 'DIR' : 'FILE' -/***/ }), -/* 894 */ -/***/ (function(module, exports, __webpack_require__) { + this.cache[abs] = this.cache[abs] || c -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(893); -var patternUtils = __webpack_require__(722); -var EntryFilter = /** @class */ (function () { - function EntryFilter(options, micromatchOptions) { - this.options = options; - this.micromatchOptions = micromatchOptions; - this.index = new Map(); - } - /** - * Returns filter for directories. - */ - EntryFilter.prototype.getFilter = function (positive, negative) { - var _this = this; - var positiveRe = patternUtils.convertPatternsToRe(positive, this.micromatchOptions); - var negativeRe = patternUtils.convertPatternsToRe(negative, this.micromatchOptions); - return function (entry) { return _this.filter(entry, positiveRe, negativeRe); }; - }; - /** - * Returns true if entry must be added to result. - */ - EntryFilter.prototype.filter = function (entry, positiveRe, negativeRe) { - // Exclude duplicate results - if (this.options.unique) { - if (this.isDuplicateEntry(entry)) { - return false; - } - this.createIndexRecord(entry); - } - // Filter files and directories by options - if (this.onlyFileFilter(entry) || this.onlyDirectoryFilter(entry)) { - return false; - } - if (this.isSkippedByAbsoluteNegativePatterns(entry, negativeRe)) { - return false; - } - return this.isMatchToPatterns(entry.path, positiveRe) && !this.isMatchToPatterns(entry.path, negativeRe); - }; - /** - * Return true if the entry already has in the cross reader index. - */ - EntryFilter.prototype.isDuplicateEntry = function (entry) { - return this.index.has(entry.path); - }; - /** - * Create record in the cross reader index. - */ - EntryFilter.prototype.createIndexRecord = function (entry) { - this.index.set(entry.path, undefined); - }; - /** - * Returns true for non-files if the «onlyFiles» option is enabled. - */ - EntryFilter.prototype.onlyFileFilter = function (entry) { - return this.options.onlyFiles && !entry.isFile(); - }; - /** - * Returns true for non-directories if the «onlyDirectories» option is enabled. - */ - EntryFilter.prototype.onlyDirectoryFilter = function (entry) { - return this.options.onlyDirectories && !entry.isDirectory(); - }; - /** - * Return true when `absolute` option is enabled and matched to the negative patterns. - */ - EntryFilter.prototype.isSkippedByAbsoluteNegativePatterns = function (entry, negativeRe) { - if (!this.options.absolute) { - return false; - } - var fullpath = pathUtils.makeAbsolute(this.options.cwd, entry.path); - return this.isMatchToPatterns(fullpath, negativeRe); - }; - /** - * Return true when entry match to provided patterns. - * - * First, just trying to apply patterns to the path. - * Second, trying to apply patterns to the path with final slash (need to micromatch to support «directory/**» patterns). - */ - EntryFilter.prototype.isMatchToPatterns = function (filepath, patternsRe) { - return patternUtils.matchAny(filepath, patternsRe) || patternUtils.matchAny(filepath + '/', patternsRe); - }; - return EntryFilter; -}()); -exports.default = EntryFilter; + if (needDir && c === 'FILE') + return false + return c +} -/***/ }), -/* 895 */ -/***/ (function(module, exports, __webpack_require__) { +GlobSync.prototype._mark = function (p) { + return common.mark(this, p) +} -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var stream = __webpack_require__(27); -var fsStat = __webpack_require__(896); -var fs_1 = __webpack_require__(900); -var FileSystemStream = /** @class */ (function (_super) { - __extends(FileSystemStream, _super); - function FileSystemStream() { - return _super !== null && _super.apply(this, arguments) || this; - } - /** - * Use stream API to read entries for Task. - */ - FileSystemStream.prototype.read = function (patterns, filter) { - var _this = this; - var filepaths = patterns.map(this.getFullEntryPath, this); - var transform = new stream.Transform({ objectMode: true }); - transform._transform = function (index, _enc, done) { - return _this.getEntry(filepaths[index], patterns[index]).then(function (entry) { - if (entry !== null && filter(entry)) { - transform.push(entry); - } - if (index === filepaths.length - 1) { - transform.end(); - } - done(); - }); - }; - for (var i = 0; i < filepaths.length; i++) { - transform.write(i); - } - return transform; - }; - /** - * Return entry for the provided path. - */ - FileSystemStream.prototype.getEntry = function (filepath, pattern) { - var _this = this; - return this.getStat(filepath) - .then(function (stat) { return _this.makeEntry(stat, pattern); }) - .catch(function () { return null; }); - }; - /** - * Return fs.Stats for the provided path. - */ - FileSystemStream.prototype.getStat = function (filepath) { - return fsStat.stat(filepath, { throwErrorOnBrokenSymlinks: false }); - }; - return FileSystemStream; -}(fs_1.default)); -exports.default = FileSystemStream; +GlobSync.prototype._makeAbs = function (f) { + return common.makeAbs(this, f) +} /***/ }), -/* 896 */ +/* 718 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; +exports.alphasort = alphasort +exports.alphasorti = alphasorti +exports.setopts = setopts +exports.ownProp = ownProp +exports.makeAbs = makeAbs +exports.finish = finish +exports.mark = mark +exports.isIgnored = isIgnored +exports.childrenIgnored = childrenIgnored -Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(897); -const statProvider = __webpack_require__(899); -/** - * Asynchronous API. - */ -function stat(path, opts) { - return new Promise((resolve, reject) => { - statProvider.async(path, optionsManager.prepare(opts), (err, stats) => err ? reject(err) : resolve(stats)); - }); -} -exports.stat = stat; -function statCallback(path, optsOrCallback, callback) { - if (typeof optsOrCallback === 'function') { - callback = optsOrCallback; /* tslint:disable-line: no-parameter-reassignment */ - optsOrCallback = undefined; /* tslint:disable-line: no-parameter-reassignment */ - } - if (typeof callback === 'undefined') { - throw new TypeError('The "callback" argument must be of type Function.'); - } - statProvider.async(path, optionsManager.prepare(optsOrCallback), callback); +function ownProp (obj, field) { + return Object.prototype.hasOwnProperty.call(obj, field) } -exports.statCallback = statCallback; -/** - * Synchronous API. - */ -function statSync(path, opts) { - return statProvider.sync(path, optionsManager.prepare(opts)); + +var path = __webpack_require__(16) +var minimatch = __webpack_require__(505) +var isAbsolute = __webpack_require__(511) +var Minimatch = minimatch.Minimatch + +function alphasorti (a, b) { + return a.toLowerCase().localeCompare(b.toLowerCase()) } -exports.statSync = statSync; +function alphasort (a, b) { + return a.localeCompare(b) +} -/***/ }), -/* 897 */ -/***/ (function(module, exports, __webpack_require__) { +function setupIgnores (self, options) { + self.ignore = options.ignore || [] -"use strict"; + if (!Array.isArray(self.ignore)) + self.ignore = [self.ignore] -Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(898); -function prepare(opts) { - const options = Object.assign({ - fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), - throwErrorOnBrokenSymlinks: true, - followSymlinks: true - }, opts); - return options; + if (self.ignore.length) { + self.ignore = self.ignore.map(ignoreMap) + } } -exports.prepare = prepare; +// ignore patterns are always in dot:true mode. +function ignoreMap (pattern) { + var gmatcher = null + if (pattern.slice(-3) === '/**') { + var gpattern = pattern.replace(/(\/\*\*)+$/, '') + gmatcher = new Minimatch(gpattern, { dot: true }) + } -/***/ }), -/* 898 */ -/***/ (function(module, exports, __webpack_require__) { + return { + matcher: new Minimatch(pattern, { dot: true }), + gmatcher: gmatcher + } +} -"use strict"; +function setopts (self, pattern, options) { + if (!options) + options = {} -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(23); -exports.FILE_SYSTEM_ADAPTER = { - lstat: fs.lstat, - stat: fs.stat, - lstatSync: fs.lstatSync, - statSync: fs.statSync -}; -function getFileSystemAdapter(fsMethods) { - if (!fsMethods) { - return exports.FILE_SYSTEM_ADAPTER; + // base-matching: just use globstar for that. + if (options.matchBase && -1 === pattern.indexOf("/")) { + if (options.noglobstar) { + throw new Error("base matching requires globstar") } - return Object.assign({}, exports.FILE_SYSTEM_ADAPTER, fsMethods); -} -exports.getFileSystemAdapter = getFileSystemAdapter; + pattern = "**/" + pattern + } + self.silent = !!options.silent + self.pattern = pattern + self.strict = options.strict !== false + self.realpath = !!options.realpath + self.realpathCache = options.realpathCache || Object.create(null) + self.follow = !!options.follow + self.dot = !!options.dot + self.mark = !!options.mark + self.nodir = !!options.nodir + if (self.nodir) + self.mark = true + self.sync = !!options.sync + self.nounique = !!options.nounique + self.nonull = !!options.nonull + self.nosort = !!options.nosort + self.nocase = !!options.nocase + self.stat = !!options.stat + self.noprocess = !!options.noprocess + self.absolute = !!options.absolute -/***/ }), -/* 899 */ -/***/ (function(module, exports, __webpack_require__) { + self.maxLength = options.maxLength || Infinity + self.cache = options.cache || Object.create(null) + self.statCache = options.statCache || Object.create(null) + self.symlinks = options.symlinks || Object.create(null) -"use strict"; + setupIgnores(self, options) -Object.defineProperty(exports, "__esModule", { value: true }); -function sync(path, options) { - const lstat = options.fs.lstatSync(path); - if (!isFollowedSymlink(lstat, options)) { - return lstat; - } - try { - const stat = options.fs.statSync(path); - stat.isSymbolicLink = () => true; - return stat; - } - catch (err) { - if (!options.throwErrorOnBrokenSymlinks) { - return lstat; - } - throw err; - } -} -exports.sync = sync; -function async(path, options, callback) { - options.fs.lstat(path, (err0, lstat) => { - if (err0) { - return callback(err0, undefined); - } - if (!isFollowedSymlink(lstat, options)) { - return callback(null, lstat); - } - options.fs.stat(path, (err1, stat) => { - if (err1) { - return options.throwErrorOnBrokenSymlinks ? callback(err1) : callback(null, lstat); - } - stat.isSymbolicLink = () => true; - callback(null, stat); - }); - }); -} -exports.async = async; -/** - * Returns `true` for followed symlink. - */ -function isFollowedSymlink(stat, options) { - return stat.isSymbolicLink() && options.followSymlinks; + self.changedCwd = false + var cwd = process.cwd() + if (!ownProp(options, "cwd")) + self.cwd = cwd + else { + self.cwd = path.resolve(options.cwd) + self.changedCwd = self.cwd !== cwd + } + + self.root = options.root || path.resolve(self.cwd, "/") + self.root = path.resolve(self.root) + if (process.platform === "win32") + self.root = self.root.replace(/\\/g, "/") + + // TODO: is an absolute `cwd` supposed to be resolved against `root`? + // e.g. { cwd: '/test', root: __dirname } === path.join(__dirname, '/test') + self.cwdAbs = isAbsolute(self.cwd) ? self.cwd : makeAbs(self, self.cwd) + if (process.platform === "win32") + self.cwdAbs = self.cwdAbs.replace(/\\/g, "/") + self.nomount = !!options.nomount + + // disable comments and negation in Minimatch. + // Note that they are not supported in Glob itself anyway. + options.nonegate = true + options.nocomment = true + + self.minimatch = new Minimatch(pattern, options) + self.options = self.minimatch.options } -exports.isFollowedSymlink = isFollowedSymlink; +function finish (self) { + var nou = self.nounique + var all = nou ? [] : Object.create(null) -/***/ }), -/* 900 */ -/***/ (function(module, exports, __webpack_require__) { + for (var i = 0, l = self.matches.length; i < l; i ++) { + var matches = self.matches[i] + if (!matches || Object.keys(matches).length === 0) { + if (self.nonull) { + // do like the shell, and spit out the literal glob + var literal = self.minimatch.globSet[i] + if (nou) + all.push(literal) + else + all[literal] = true + } + } else { + // had matches + var m = Object.keys(matches) + if (nou) + all.push.apply(all, m) + else + m.forEach(function (m) { + all[m] = true + }) + } + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(16); -var FileSystem = /** @class */ (function () { - function FileSystem(options) { - this.options = options; - } - /** - * Return full path to entry. - */ - FileSystem.prototype.getFullEntryPath = function (filepath) { - return path.resolve(this.options.cwd, filepath); - }; - /** - * Return an implementation of the Entry interface. - */ - FileSystem.prototype.makeEntry = function (stat, pattern) { - stat.path = pattern; - stat.depth = pattern.split('/').length; - return stat; - }; - return FileSystem; -}()); -exports.default = FileSystem; + if (!nou) + all = Object.keys(all) + if (!self.nosort) + all = all.sort(self.nocase ? alphasorti : alphasort) -/***/ }), -/* 901 */ -/***/ (function(module, exports, __webpack_require__) { + // at *some* point we statted all of these + if (self.mark) { + for (var i = 0; i < all.length; i++) { + all[i] = self._mark(all[i]) + } + if (self.nodir) { + all = all.filter(function (e) { + var notDir = !(/\/$/.test(e)) + var c = self.cache[e] || self.cache[makeAbs(self, e)] + if (notDir && c) + notDir = c !== 'DIR' && !Array.isArray(c) + return notDir + }) + } + } -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var stream = __webpack_require__(27); -var readdir = __webpack_require__(878); -var reader_1 = __webpack_require__(891); -var fs_stream_1 = __webpack_require__(895); -var TransformStream = /** @class */ (function (_super) { - __extends(TransformStream, _super); - function TransformStream(reader) { - var _this = _super.call(this, { objectMode: true }) || this; - _this.reader = reader; - return _this; - } - TransformStream.prototype._transform = function (entry, _encoding, callback) { - callback(null, this.reader.transform(entry)); - }; - return TransformStream; -}(stream.Transform)); -var ReaderStream = /** @class */ (function (_super) { - __extends(ReaderStream, _super); - function ReaderStream() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(ReaderStream.prototype, "fsAdapter", { - /** - * Returns FileSystem adapter. - */ - get: function () { - return new fs_stream_1.default(this.options); - }, - enumerable: true, - configurable: true - }); - /** - * Use stream API to read entries for Task. - */ - ReaderStream.prototype.read = function (task) { - var _this = this; - var root = this.getRootDirectory(task); - var options = this.getReaderOptions(task); - var transform = new TransformStream(this); - var readable = this.api(root, task, options); - return readable - .on('error', function (err) { return _this.isEnoentCodeError(err) ? null : transform.emit('error', err); }) - .pipe(transform); - }; - /** - * Returns founded paths. - */ - ReaderStream.prototype.api = function (root, task, options) { - if (task.dynamic) { - return this.dynamicApi(root, options); - } - return this.staticApi(task, options); - }; - /** - * Api for dynamic tasks. - */ - ReaderStream.prototype.dynamicApi = function (root, options) { - return readdir.readdirStreamStat(root, options); - }; - /** - * Api for static tasks. - */ - ReaderStream.prototype.staticApi = function (task, options) { - return this.fsAdapter.read(task.patterns, options.filter); - }; - return ReaderStream; -}(reader_1.default)); -exports.default = ReaderStream; + if (self.ignore.length) + all = all.filter(function(m) { + return !isIgnored(self, m) + }) + self.found = all +} -/***/ }), -/* 902 */ -/***/ (function(module, exports, __webpack_require__) { +function mark (self, p) { + var abs = makeAbs(self, p) + var c = self.cache[abs] + var m = p + if (c) { + var isDir = c === 'DIR' || Array.isArray(c) + var slash = p.slice(-1) === '/' -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(878); -var reader_1 = __webpack_require__(891); -var fs_sync_1 = __webpack_require__(903); -var ReaderSync = /** @class */ (function (_super) { - __extends(ReaderSync, _super); - function ReaderSync() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(ReaderSync.prototype, "fsAdapter", { - /** - * Returns FileSystem adapter. - */ - get: function () { - return new fs_sync_1.default(this.options); - }, - enumerable: true, - configurable: true - }); - /** - * Use sync API to read entries for Task. - */ - ReaderSync.prototype.read = function (task) { - var root = this.getRootDirectory(task); - var options = this.getReaderOptions(task); - try { - var entries = this.api(root, task, options); - return entries.map(this.transform, this); - } - catch (err) { - if (this.isEnoentCodeError(err)) { - return []; - } - throw err; - } - }; - /** - * Returns founded paths. - */ - ReaderSync.prototype.api = function (root, task, options) { - if (task.dynamic) { - return this.dynamicApi(root, options); - } - return this.staticApi(task, options); - }; - /** - * Api for dynamic tasks. - */ - ReaderSync.prototype.dynamicApi = function (root, options) { - return readdir.readdirSyncStat(root, options); - }; - /** - * Api for static tasks. - */ - ReaderSync.prototype.staticApi = function (task, options) { - return this.fsAdapter.read(task.patterns, options.filter); - }; - return ReaderSync; -}(reader_1.default)); -exports.default = ReaderSync; + if (isDir && !slash) + m += '/' + else if (!isDir && slash) + m = m.slice(0, -1) + if (m !== p) { + var mabs = makeAbs(self, m) + self.statCache[mabs] = self.statCache[abs] + self.cache[mabs] = self.cache[abs] + } + } -/***/ }), -/* 903 */ -/***/ (function(module, exports, __webpack_require__) { + return m +} -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(896); -var fs_1 = __webpack_require__(900); -var FileSystemSync = /** @class */ (function (_super) { - __extends(FileSystemSync, _super); - function FileSystemSync() { - return _super !== null && _super.apply(this, arguments) || this; - } - /** - * Use sync API to read entries for Task. - */ - FileSystemSync.prototype.read = function (patterns, filter) { - var _this = this; - var entries = []; - patterns.forEach(function (pattern) { - var filepath = _this.getFullEntryPath(pattern); - var entry = _this.getEntry(filepath, pattern); - if (entry === null || !filter(entry)) { - return; - } - entries.push(entry); - }); - return entries; - }; - /** - * Return entry for the provided path. - */ - FileSystemSync.prototype.getEntry = function (filepath, pattern) { - try { - var stat = this.getStat(filepath); - return this.makeEntry(stat, pattern); - } - catch (err) { - return null; - } - }; - /** - * Return fs.Stats for the provided path. - */ - FileSystemSync.prototype.getStat = function (filepath) { - return fsStat.statSync(filepath, { throwErrorOnBrokenSymlinks: false }); - }; - return FileSystemSync; -}(fs_1.default)); -exports.default = FileSystemSync; +// lotta situps... +function makeAbs (self, f) { + var abs = f + if (f.charAt(0) === '/') { + abs = path.join(self.root, f) + } else if (isAbsolute(f) || f === '') { + abs = f + } else if (self.changedCwd) { + abs = path.resolve(self.cwd, f) + } else { + abs = path.resolve(f) + } + if (process.platform === 'win32') + abs = abs.replace(/\\/g, '/') -/***/ }), -/* 904 */ -/***/ (function(module, exports, __webpack_require__) { + return abs +} -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -/** - * Flatten nested arrays (max depth is 2) into a non-nested array of non-array items. - */ -function flatten(items) { - return items.reduce(function (collection, item) { return [].concat(collection, item); }, []); -} -exports.flatten = flatten; +// Return true, if pattern ends with globstar '**', for the accompanying parent directory. +// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents +function isIgnored (self, path) { + if (!self.ignore.length) + return false -/***/ }), -/* 905 */ -/***/ (function(module, exports, __webpack_require__) { + return self.ignore.some(function(item) { + return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) + }) +} -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var merge2 = __webpack_require__(590); -/** - * Merge multiple streams and propagate their errors into one stream in parallel. - */ -function merge(streams) { - var mergedStream = merge2(streams); - streams.forEach(function (stream) { - stream.on('error', function (err) { return mergedStream.emit('error', err); }); - }); - return mergedStream; -} -exports.merge = merge; +function childrenIgnored (self, path) { + if (!self.ignore.length) + return false + + return self.ignore.some(function(item) { + return !!(item.gmatcher && item.gmatcher.match(path)) + }) +} /***/ }), -/* 906 */ +/* 719 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const pathType = __webpack_require__(907); +const pathType = __webpack_require__(720); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -105865,13 +81870,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 907 */ +/* 720 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const pify = __webpack_require__(908); +const pify = __webpack_require__(721); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -105914,7 +81919,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 908 */ +/* 721 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106005,17 +82010,17 @@ module.exports = (obj, opts) => { /***/ }), -/* 909 */ +/* 722 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); const path = __webpack_require__(16); -const fastGlob = __webpack_require__(718); -const gitIgnore = __webpack_require__(910); -const pify = __webpack_require__(911); -const slash = __webpack_require__(912); +const fastGlob = __webpack_require__(596); +const gitIgnore = __webpack_require__(723); +const pify = __webpack_require__(724); +const slash = __webpack_require__(725); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -106113,7 +82118,7 @@ module.exports.sync = options => { /***/ }), -/* 910 */ +/* 723 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -106582,7 +82587,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 911 */ +/* 724 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106657,7 +82662,7 @@ module.exports = (input, options) => { /***/ }), -/* 912 */ +/* 725 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106675,17 +82680,17 @@ module.exports = input => { /***/ }), -/* 913 */ +/* 726 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); const {constants: fsConstants} = __webpack_require__(23); -const pEvent = __webpack_require__(914); -const CpFileError = __webpack_require__(917); -const fs = __webpack_require__(921); -const ProgressEmitter = __webpack_require__(924); +const pEvent = __webpack_require__(727); +const CpFileError = __webpack_require__(730); +const fs = __webpack_require__(734); +const ProgressEmitter = __webpack_require__(737); const cpFileAsync = async (source, destination, options, progressEmitter) => { let readError; @@ -106799,12 +82804,12 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 914 */ +/* 727 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pTimeout = __webpack_require__(915); +const pTimeout = __webpack_require__(728); const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; @@ -107095,12 +83100,12 @@ module.exports.iterator = (emitter, event, options) => { /***/ }), -/* 915 */ +/* 728 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pFinally = __webpack_require__(916); +const pFinally = __webpack_require__(729); class TimeoutError extends Error { constructor(message) { @@ -107146,7 +83151,7 @@ module.exports.TimeoutError = TimeoutError; /***/ }), -/* 916 */ +/* 729 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -107168,12 +83173,12 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 917 */ +/* 730 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(918); +const NestedError = __webpack_require__(731); class CpFileError extends NestedError { constructor(message, nested) { @@ -107187,10 +83192,10 @@ module.exports = CpFileError; /***/ }), -/* 918 */ +/* 731 */ /***/ (function(module, exports, __webpack_require__) { -var inherits = __webpack_require__(919); +var inherits = __webpack_require__(732); var NestedError = function (message, nested) { this.nested = nested; @@ -107241,7 +83246,7 @@ module.exports = NestedError; /***/ }), -/* 919 */ +/* 732 */ /***/ (function(module, exports, __webpack_require__) { try { @@ -107249,12 +83254,12 @@ try { if (typeof util.inherits !== 'function') throw ''; module.exports = util.inherits; } catch (e) { - module.exports = __webpack_require__(920); + module.exports = __webpack_require__(733); } /***/ }), -/* 920 */ +/* 733 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { @@ -107283,16 +83288,16 @@ if (typeof Object.create === 'function') { /***/ }), -/* 921 */ +/* 734 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(29); const fs = __webpack_require__(22); -const makeDir = __webpack_require__(922); -const pEvent = __webpack_require__(914); -const CpFileError = __webpack_require__(917); +const makeDir = __webpack_require__(735); +const pEvent = __webpack_require__(727); +const CpFileError = __webpack_require__(730); const stat = promisify(fs.stat); const lstat = promisify(fs.lstat); @@ -107389,7 +83394,7 @@ exports.copyFileSync = (source, destination, flags) => { /***/ }), -/* 922 */ +/* 735 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -107397,7 +83402,7 @@ exports.copyFileSync = (source, destination, flags) => { const fs = __webpack_require__(23); const path = __webpack_require__(16); const {promisify} = __webpack_require__(29); -const semver = __webpack_require__(923); +const semver = __webpack_require__(736); const defaults = { mode: 0o777 & (~process.umask()), @@ -107546,7 +83551,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 923 */ +/* 736 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -109148,7 +85153,7 @@ function coerce (version, options) { /***/ }), -/* 924 */ +/* 737 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -109189,7 +85194,7 @@ module.exports = ProgressEmitter; /***/ }), -/* 925 */ +/* 738 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -109235,12 +85240,12 @@ exports.default = module.exports; /***/ }), -/* 926 */ +/* 739 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(927); +const NestedError = __webpack_require__(740); class CpyError extends NestedError { constructor(message, nested) { @@ -109254,7 +85259,7 @@ module.exports = CpyError; /***/ }), -/* 927 */ +/* 740 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(29).inherits; @@ -109310,7 +85315,7 @@ module.exports = NestedError; /***/ }), -/* 928 */ +/* 741 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; diff --git a/x-pack/legacy/plugins/siem/common/graphql/root/schema.gql.ts b/x-pack/legacy/plugins/siem/common/graphql/root/schema.gql.ts index 1665334827e8e..721270d1d6fcd 100644 --- a/x-pack/legacy/plugins/siem/common/graphql/root/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/common/graphql/root/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const rootSchema = gql` schema { diff --git a/x-pack/legacy/plugins/siem/common/graphql/shared/schema.gql.ts b/x-pack/legacy/plugins/siem/common/graphql/shared/schema.gql.ts index d043c1587d3c3..43c87caa9f181 100644 --- a/x-pack/legacy/plugins/siem/common/graphql/shared/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/common/graphql/shared/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const sharedSchema = gql` input TimerangeInput { diff --git a/x-pack/legacy/plugins/siem/public/app/app.tsx b/x-pack/legacy/plugins/siem/public/app/app.tsx index 7413aeab549db..c65b016068f9d 100644 --- a/x-pack/legacy/plugins/siem/public/app/app.tsx +++ b/x-pack/legacy/plugins/siem/public/app/app.tsx @@ -6,7 +6,7 @@ import { createHashHistory, History } from 'history'; import React, { memo, useMemo, FC } from 'react'; -import { ApolloProvider } from 'react-apollo'; +import { ApolloProvider } from '@apollo/client'; import { Store } from 'redux'; import { Provider as ReduxStoreProvider } from 'react-redux'; import { ThemeProvider } from 'styled-components'; @@ -30,8 +30,6 @@ import { createStore, createInitialState } from '../store'; import { GlobalToaster, ManageGlobalToaster } from '../components/toasters'; import { MlCapabilitiesProvider } from '../components/ml/permissions/ml_capabilities_provider'; -import { ApolloClientContext } from '../utils/apollo_context'; - interface AppPluginRootComponentProps { apolloClient: AppApolloClient; history: History; @@ -48,15 +46,13 @@ const AppPluginRootComponent: React.FC = ({ - - - - - - - - - + + + + + + + diff --git a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/drag_drop_context_wrapper.test.tsx b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/drag_drop_context_wrapper.test.tsx index 9e8bde8d9ff92..efe5aed46f16a 100644 --- a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/drag_drop_context_wrapper.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/drag_drop_context_wrapper.test.tsx @@ -6,7 +6,7 @@ import { mount, shallow } from 'enzyme'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import { mockBrowserFields, mocksSource } from '../../containers/source/mock'; import { TestProviders } from '../../mock'; @@ -20,7 +20,7 @@ describe('DragDropContextWrapper', () => { const wrapper = shallow( - + {message} diff --git a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.test.tsx b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.test.tsx index e846c923c5cbe..92adc1a9adb7a 100644 --- a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.test.tsx @@ -6,7 +6,7 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import { mockBrowserFields, mocksSource } from '../../containers/source/mock'; import { TestProviders } from '../../mock'; @@ -24,7 +24,7 @@ describe('DraggableWrapper', () => { test('it renders against the snapshot', () => { const wrapper = shallow( - + message} /> diff --git a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/droppable_wrapper.test.tsx b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/droppable_wrapper.test.tsx index bd2f01721290f..aa3ad8f47af21 100644 --- a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/droppable_wrapper.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/droppable_wrapper.test.tsx @@ -6,7 +6,7 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import { mockBrowserFields, mocksSource } from '../../containers/source/mock'; import { TestProviders } from '../../mock'; @@ -24,7 +24,7 @@ describe('DroppableWrapper', () => { const wrapper = shallow( - + {message} diff --git a/x-pack/legacy/plugins/siem/public/components/event_details/columns.tsx b/x-pack/legacy/plugins/siem/public/components/event_details/columns.tsx index e9903ce66d799..c62f44e1c5e31 100644 --- a/x-pack/legacy/plugins/siem/public/components/event_details/columns.tsx +++ b/x-pack/legacy/plugins/siem/public/components/event_details/columns.tsx @@ -20,7 +20,7 @@ import { Draggable } from 'react-beautiful-dnd'; import styled from 'styled-components'; import { BrowserFields } from '../../containers/source'; -import { ToStringArray } from '../../graphql/types'; +import { Scalars } from '../../graphql/types'; import { WithCopyToClipboard } from '../../lib/clipboard/with_copy_to_clipboard'; import { ColumnHeaderOptions } from '../../store/timeline/model'; import { DragEffects } from '../drag_and_drop/draggable_wrapper'; @@ -159,7 +159,7 @@ export const getColumns = ({ name: i18n.VALUE, sortable: true, truncateText: false, - render: (values: ToStringArray | null | undefined, data: EventFieldsData) => ( + render: (values: Scalars['ToStringArray'] | null | undefined, data: EventFieldsData) => ( {values != null && values.map((value, i) => ( diff --git a/x-pack/legacy/plugins/siem/public/components/event_details/helpers.tsx b/x-pack/legacy/plugins/siem/public/components/event_details/helpers.tsx index 5d9c9d82490bb..ef002abbd252d 100644 --- a/x-pack/legacy/plugins/siem/public/components/event_details/helpers.tsx +++ b/x-pack/legacy/plugins/siem/public/components/event_details/helpers.tsx @@ -12,7 +12,7 @@ import { DEFAULT_DATE_COLUMN_MIN_WIDTH, DEFAULT_COLUMN_MIN_WIDTH, } from '../timeline/body/constants'; -import { ToStringArray } from '../../graphql/types'; +import { Scalars } from '../../graphql/types'; import * as i18n from './translations'; @@ -40,7 +40,7 @@ export interface Item { field: JSX.Element; fieldId: string; type: string; - values: ToStringArray; + values: Scalars['ToStringArray']; } export const getColumnHeaderFromBrowserField = ({ diff --git a/x-pack/legacy/plugins/siem/public/components/events_viewer/events_viewer.test.tsx b/x-pack/legacy/plugins/siem/public/components/events_viewer/events_viewer.test.tsx index d3cdf9886e469..756944b83c316 100644 --- a/x-pack/legacy/plugins/siem/public/components/events_viewer/events_viewer.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/events_viewer/events_viewer.test.tsx @@ -5,7 +5,8 @@ */ import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; +import { act } from '@testing-library/react'; import useResizeObserver from 'use-resize-observer/polyfilled'; import { mockIndexPattern, TestProviders } from '../../mock'; @@ -52,7 +53,7 @@ describe('EventsViewer', () => { ); - await wait(); + await act(() => wait()); wrapper.update(); expect( @@ -77,7 +78,7 @@ describe('EventsViewer', () => { ); - await wait(); + await act(() => wait()); wrapper.update(); expect( @@ -102,7 +103,7 @@ describe('EventsViewer', () => { ); - await wait(); + await act(() => wait()); wrapper.update(); expect( @@ -128,7 +129,7 @@ describe('EventsViewer', () => { ); - await wait(); + await act(() => wait()); wrapper.update(); defaultHeaders.forEach(h => diff --git a/x-pack/legacy/plugins/siem/public/components/events_viewer/events_viewer.tsx b/x-pack/legacy/plugins/siem/public/components/events_viewer/events_viewer.tsx index a913186d9ad3b..f460ea24d5447 100644 --- a/x-pack/legacy/plugins/siem/public/components/events_viewer/events_viewer.tsx +++ b/x-pack/legacy/plugins/siem/public/components/events_viewer/events_viewer.tsx @@ -201,7 +201,6 @@ const EventsViewerComponent: React.FC = ({ getUpdatedAt={getUpdatedAt} hasNextPage={getOr(false, 'hasNextPage', pageInfo)!} height={footerHeight} - isEventViewer={true} isLive={isLive} isLoading={loading} itemsCount={events.length} @@ -243,7 +242,7 @@ export const EventsViewer = React.memo( prevProps.kqlMode === nextProps.kqlMode && deepEqual(prevProps.query, nextProps.query) && prevProps.start === nextProps.start && - prevProps.sort === nextProps.sort && + deepEqual(prevProps.sort, nextProps.sort) && deepEqual(prevProps.timelineTypeContext, nextProps.timelineTypeContext) && prevProps.utilityBar === nextProps.utilityBar ); diff --git a/x-pack/legacy/plugins/siem/public/components/events_viewer/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/events_viewer/index.test.tsx index 6f614c1e32f65..034579b9d157e 100644 --- a/x-pack/legacy/plugins/siem/public/components/events_viewer/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/events_viewer/index.test.tsx @@ -5,7 +5,8 @@ */ import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; +import { act } from '@testing-library/react'; import useResizeObserver from 'use-resize-observer/polyfilled'; import { wait } from '../../lib/helpers'; @@ -51,7 +52,7 @@ describe('StatefulEventsViewer', () => { ); - await wait(); + await act(() => wait()); wrapper.update(); expect( @@ -77,7 +78,7 @@ describe('StatefulEventsViewer', () => { ); - await wait(); + await act(() => wait()); wrapper.update(); expect(wrapper.find(`InspectButtonContainer`).exists()).toBe(true); diff --git a/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx b/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx index 22fc9f27ce26c..139dcd1943fad 100644 --- a/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/flyout/index.tsx @@ -9,6 +9,7 @@ import { defaultTo, getOr } from 'lodash/fp'; import React, { useCallback } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal'; import { State, timelineSelectors } from '../../store'; import { DataProvider } from '../timeline/data_providers/data_provider'; @@ -90,7 +91,17 @@ export const FlyoutComponent = React.memo( /> ); - } + }, + (prevProps, nextProps) => + prevProps.children === nextProps.children && + deepEqual(prevProps.dataProviders, nextProps.dataProviders) && + prevProps.flyoutHeight === nextProps.flyoutHeight && + prevProps.headerHeight === nextProps.headerHeight && + prevProps.show === nextProps.show && + prevProps.showTimeline === nextProps.showTimeline && + prevProps.timelineId === nextProps.timelineId && + prevProps.usersViewing === nextProps.usersViewing && + prevProps.width === nextProps.width ); FlyoutComponent.displayName = 'FlyoutComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/header_global/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/header_global/__snapshots__/index.test.tsx.snap index 25374c63fa897..6b4af62586c19 100644 --- a/x-pack/legacy/plugins/siem/public/components/header_global/__snapshots__/index.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/header_global/__snapshots__/index.test.tsx.snap @@ -9,11 +9,106 @@ exports[`HeaderGlobal it renders 1`] = ` justifyContent="spaceBetween" wrap={true} > - + + + + + + + + + + + + - - + + + + + + + Add data + + + + `; diff --git a/x-pack/legacy/plugins/siem/public/components/header_global/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/header_global/index.test.tsx index 098de39bbfef5..6c20daeab4cbc 100644 --- a/x-pack/legacy/plugins/siem/public/components/header_global/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/header_global/index.test.tsx @@ -17,10 +17,15 @@ jest.mock('ui/new_platform'); jest.mock('../search_bar', () => ({ SiemSearchBar: () => null, })); +jest.mock('../../containers/source', () => ({ + useWithSource: () => ({ + contentAvailable: true, + }), +})); describe('HeaderGlobal', () => { test('it renders', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); }); diff --git a/x-pack/legacy/plugins/siem/public/components/header_global/index.tsx b/x-pack/legacy/plugins/siem/public/components/header_global/index.tsx index a12fab8a4f5d9..55c67a5af69ea 100644 --- a/x-pack/legacy/plugins/siem/public/components/header_global/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/header_global/index.tsx @@ -16,7 +16,6 @@ import { getOverviewUrl } from '../link_to'; import { MlPopover } from '../ml_popover/ml_popover'; import { SiemNavigation } from '../navigation'; import * as i18n from './translations'; -import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source'; const Wrapper = styled.header` ${({ theme }) => css` @@ -34,65 +33,64 @@ const FlexItem = styled(EuiFlexItem)` FlexItem.displayName = 'FlexItem'; interface HeaderGlobalProps { + contentAvailable: boolean; hideDetectionEngine?: boolean; } -export const HeaderGlobal = React.memo(({ hideDetectionEngine = false }) => ( - - - - {({ indicesExist }) => ( - <> - - - - - - - +export const HeaderGlobal = React.memo( + ({ contentAvailable, hideDetectionEngine = false }) => ( + + + <> + + + + + + + - - {indicesExistOrDataTemporarilyUnavailable(indicesExist) ? ( - key !== SiemPageName.detections, navTabs) - : navTabs - } - /> - ) : ( - key === SiemPageName.overview, navTabs)} - /> - )} - - - - - - - {indicesExistOrDataTemporarilyUnavailable(indicesExist) && ( - - - + + {contentAvailable ? ( + key !== SiemPageName.detections, navTabs) + : navTabs + } + /> + ) : ( + key === SiemPageName.overview, navTabs)} + /> )} + + + + + + {contentAvailable && ( - - {i18n.BUTTON_ADD_DATA} - + - - - - )} - - - -)); + )} + + + + {i18n.BUTTON_ADD_DATA} + + + + + + + + ) +); HeaderGlobal.displayName = 'HeaderGlobal'; diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/helpers.ts b/x-pack/legacy/plugins/siem/public/components/open_timeline/helpers.ts index 4f7d6cd64f1d9..3dd1b145e7d09 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/helpers.ts +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/helpers.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import ApolloClient from 'apollo-client'; +import { ApolloClient } from '@apollo/client'; import { getOr, set } from 'lodash/fp'; import { Action } from 'typescript-fsa'; diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/index.test.tsx index 520e2094fb336..d3911fdf18f09 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/index.test.tsx @@ -6,14 +6,15 @@ import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; import { mount } from 'enzyme'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import React from 'react'; import { ThemeProvider } from 'styled-components'; +import { act } from '@testing-library/react'; import { wait } from '../../lib/helpers'; -import { TestProviderWithoutDragAndDrop, apolloClient } from '../../mock/test_providers'; -import { mockOpenTimelineQueryResults } from '../../mock/timeline_results'; -import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines/timelines_page'; +import { TestProviderWithoutDragAndDrop } from '../../mock/test_providers'; +import { mockOpenTimelineQueryResults, MockedProvidedQuery } from '../../mock/timeline_results'; +import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines'; import { StatefulOpenTimeline } from '.'; import { NotePreviews } from './note_previews'; @@ -24,15 +25,19 @@ jest.mock('../../lib/kibana'); describe('StatefulOpenTimeline', () => { const theme = () => ({ eui: euiDarkVars, darkMode: true }); const title = 'All Timelines / Open Timelines'; + let mocks: MockedProvidedQuery[]; + + beforeEach(() => { + mocks = mockOpenTimelineQueryResults; + }); test('it has the expected initial state', () => { const wrapper = mount( - + { }); describe('#onQueryChange', () => { - test('it updates the query state with the expected trimmed value when the user enters a query', () => { + test('it updates the query state with the expected trimmed value when the user enters a query', async () => { const wrapper = mount( - + { ); + wrapper .find('[data-test-subj="search-bar"] input') .simulate('keyup', { keyCode: 13, target: { value: ' abcd ' } }); + expect( wrapper .find('[data-test-subj="search-row"]') @@ -92,9 +98,8 @@ describe('StatefulOpenTimeline', () => { const wrapper = mount( - + { ); - await wait(); + await act(() => wait()); wrapper .find('[data-test-subj="search-bar"] input') @@ -122,9 +127,8 @@ describe('StatefulOpenTimeline', () => { const wrapper = mount( - + { ); - await wait(); + await act(() => wait()); wrapper .find('[data-test-subj="search-bar"] input') @@ -154,9 +158,8 @@ describe('StatefulOpenTimeline', () => { const wrapper = mount( - + { ); - await wait(); + await act(() => wait()); expect( wrapper @@ -185,9 +188,8 @@ describe('StatefulOpenTimeline', () => { const wrapper = mount( - + { ); - await wait(); + await act(() => wait()); wrapper .find('.euiCheckbox__input') @@ -231,9 +233,8 @@ describe('StatefulOpenTimeline', () => { const wrapper = mount( - + { ); - await wait(); + await act(() => wait()); wrapper .find('.euiCheckbox__input') @@ -274,10 +275,9 @@ describe('StatefulOpenTimeline', () => { const wrapper = mount( - + { ); - await wait(); + await act(() => wait()); wrapper .find('.euiCheckbox__input') @@ -308,10 +308,9 @@ describe('StatefulOpenTimeline', () => { const wrapper = mount( - + { const wrapper = mount( - + { const wrapper = mount( - + { ); - await wait(); + await act(() => wait()); wrapper.update(); expect( @@ -423,10 +420,11 @@ describe('StatefulOpenTimeline', () => { '10849df0-7b44-11e9-a608-ab3d811609': ( ({ ...note, savedObjectId: note.noteId }) - ) + mocks[0].result.data!.getAllTimeline.timeline[0].notes != null + ? mocks[0].result.data!.getAllTimeline.timeline[0].notes.map(note => ({ + ...note, + savedObjectId: note.noteId, + })) : [] } /> @@ -438,10 +436,9 @@ describe('StatefulOpenTimeline', () => { const wrapper = mount( - + { ); - await wait(); + await act(() => wait()); wrapper.update(); @@ -474,10 +471,9 @@ describe('StatefulOpenTimeline', () => { const wrapper = mount( - + { ); - await wait(); + await act(() => wait()); expect( wrapper @@ -497,15 +493,14 @@ describe('StatefulOpenTimeline', () => { ).toEqual(title); }); - describe('#resetSelectionState', () => { + describe.skip('#resetSelectionState', () => { test('when the user deletes selected timelines, resetSelectionState is invoked to clear the selection state', async () => { const wrapper = mount( - + { .find('[data-test-subj="open-timeline"]') .last() .prop('selectedItems'); - await wait(); + await act(() => wait()); expect(getSelectedItem().length).toEqual(0); wrapper .find('.euiCheckbox__input') @@ -537,11 +532,10 @@ describe('StatefulOpenTimeline', () => { test('it renders the expected count of matching timelines when no query has been entered', async () => { const wrapper = mount( - + { ); - await wait(); + await act(() => wait()); wrapper.update(); + await act(() => wait()); + expect( wrapper .find('[data-test-subj="query-message"]') @@ -570,10 +566,9 @@ describe('StatefulOpenTimeline', () => { const wrapper = mount( - + { ); - await wait(); + await act(() => wait()); wrapper .find( - `[data-test-subj="title-${ - mockOpenTimelineQueryResults[0].result.data!.getAllTimeline.timeline[0].savedObjectId - }"]` + `[data-test-subj="title-${mocks[0].result.data!.getAllTimeline.timeline[0].savedObjectId}"]` ) .first() .simulate('click'); expect(onOpenTimeline).toHaveBeenCalledWith({ duplicate: false, - timelineId: mockOpenTimelineQueryResults[0].result.data!.getAllTimeline.timeline[0] - .savedObjectId, + timelineId: mocks[0].result.data!.getAllTimeline.timeline[0].savedObjectId, }); }); @@ -608,10 +600,9 @@ describe('StatefulOpenTimeline', () => { const wrapper = mount( - + { ); - await wait(); + await act(() => wait()); wrapper .find('[data-test-subj="open-duplicate"]') diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/index.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/index.tsx index 26a7487fee52b..455a60b89b9ab 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import ApolloClient from 'apollo-client'; +import { useApolloClient } from '@apollo/client'; import React, { useEffect, useState, useCallback } from 'react'; import { connect, ConnectedProps } from 'react-redux'; @@ -43,7 +43,6 @@ import { import { DEFAULT_SORT_FIELD, DEFAULT_SORT_DIRECTION } from './constants'; interface OwnProps { - apolloClient: ApolloClient; /** Displays open timeline in modal */ isModal: boolean; closeModalTimeline?: () => void; @@ -68,7 +67,6 @@ export const getSelectedTimelineIds = (selectedItems: OpenTimelineResult[]): str /** Manages the state (e.g table selection) of the (pure) `OpenTimeline` component */ export const StatefulOpenTimelineComponent = React.memo( ({ - apolloClient, closeModalTimeline, createNewTimeline, defaultPageSize, @@ -80,6 +78,7 @@ export const StatefulOpenTimelineComponent = React.memo( updateTimeline, updateIsLoading, }) => { + const apolloClient = useApolloClient(); /** Required by EuiTable for expandable rows: a map of `TimelineResult.savedObjectId` to rendered notes */ const [itemIdToExpandedNotesRowMap, setItemIdToExpandedNotesRowMap] = useState< Record diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline.test.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline.test.tsx index a1ca7812bba34..6df1039b68716 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline.test.tsx @@ -10,7 +10,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines/timelines_page'; +import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines'; import { OpenTimelineResult } from './types'; import { TimelinesTableProps } from './timelines_table'; import { mockTimelineResults } from '../../mock/timeline_results'; diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/index.test.tsx index ca8fa50c572fe..4d9ecd0d6052f 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/index.test.tsx @@ -7,8 +7,9 @@ import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; import { mount } from 'enzyme'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import { ThemeProvider } from 'styled-components'; +import { act } from '@testing-library/react'; import { wait } from '../../../lib/helpers'; import { TestProviderWithoutDragAndDrop } from '../../../mock/test_providers'; @@ -17,9 +18,6 @@ import { mockOpenTimelineQueryResults } from '../../../mock/timeline_results'; import { OpenTimelineModal } from '.'; jest.mock('../../../lib/kibana'); -jest.mock('../../../utils/apollo_context', () => ({ - useApolloClient: () => ({}), -})); describe('OpenTimelineModal', () => { const theme = () => ({ eui: euiDarkVars, darkMode: true }); @@ -35,7 +33,7 @@ describe('OpenTimelineModal', () => { ); - await wait(); + await act(() => wait()); wrapper.update(); diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/index.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/index.tsx index c530929a3c96e..5f5792efc1eb8 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/index.tsx @@ -8,7 +8,6 @@ import { EuiModal, EuiOverlayMask } from '@elastic/eui'; import React from 'react'; import { TimelineModel } from '../../../store/timeline/model'; -import { useApolloClient } from '../../../utils/apollo_context'; import * as i18n from '../translations'; import { ActionTimelineToShow } from '../types'; @@ -25,31 +24,24 @@ const DEFAULT_SEARCH_RESULTS_PER_PAGE = 10; const OPEN_TIMELINE_MODAL_WIDTH = 1000; // px export const OpenTimelineModal = React.memo( - ({ hideActions = [], modalTitle, onClose, onOpen }) => { - const apolloClient = useApolloClient(); - - if (!apolloClient) return null; - - return ( - - - - - - ); - } + ({ hideActions = [], modalTitle, onClose, onOpen }) => ( + + + + + + ) ); OpenTimelineModal.displayName = 'OpenTimelineModal'; diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/open_timeline_modal_body.test.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/open_timeline_modal_body.test.tsx index 2c3adb138b7ac..df24a43057a18 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/open_timeline_modal_body.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/open_timeline_modal_body.test.tsx @@ -10,7 +10,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines/timelines_page'; +import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines'; import { OpenTimelineResult } from '../types'; import { TimelinesTableProps } from '../timelines_table'; import { mockTimelineResults } from '../../../mock/timeline_results'; diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/open_timeline_modal_button.test.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/open_timeline_modal_button.test.tsx index 66947a313f5e5..cafcc031f7a81 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/open_timeline_modal_button.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/open_timeline_modal/open_timeline_modal_button.test.tsx @@ -7,8 +7,9 @@ import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; import { mount } from 'enzyme'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import { ThemeProvider } from 'styled-components'; +import { act } from '@testing-library/react'; import { wait } from '../../../lib/helpers'; import { TestProviderWithoutDragAndDrop } from '../../../mock/test_providers'; @@ -29,7 +30,7 @@ describe('OpenTimelineModalButton', () => { ); - await wait(); + await act(() => wait()); wrapper.update(); @@ -54,7 +55,7 @@ describe('OpenTimelineModalButton', () => { ); - await wait(); + await act(() => wait()); wrapper .find('[data-test-subj="open-timeline-button"]') diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/actions_columns.test.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/actions_columns.test.tsx index eec11f571328f..26e0aa1ff5751 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/actions_columns.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/actions_columns.test.tsx @@ -11,7 +11,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines/timelines_page'; +import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines'; import { mockTimelineResults } from '../../../mock/timeline_results'; import { OpenTimelineResult } from '../types'; import { TimelinesTable } from '.'; diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/common_columns.test.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/common_columns.test.tsx index 0f2cda9d79f0b..bd5da06a37bbc 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/common_columns.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/common_columns.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { ThemeProvider } from 'styled-components'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines/timelines_page'; +import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines'; import { getEmptyValue } from '../../empty_value'; import { OpenTimelineResult } from '../types'; import { mockTimelineResults } from '../../../mock/timeline_results'; diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/extended_columns.test.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/extended_columns.test.tsx index 4cbe1e45c473b..b6554aa794f9c 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/extended_columns.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/extended_columns.test.tsx @@ -10,7 +10,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines/timelines_page'; +import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines'; import { getEmptyValue } from '../../empty_value'; import { mockTimelineResults } from '../../../mock/timeline_results'; import { OpenTimelineResult } from '../types'; diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/icon_header_columns.test.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/icon_header_columns.test.tsx index 31377d176acac..3f06fbeb5921c 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/icon_header_columns.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/icon_header_columns.test.tsx @@ -10,7 +10,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines/timelines_page'; +import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines'; import { mockTimelineResults } from '../../../mock/timeline_results'; import { TimelinesTable } from '.'; import { OpenTimelineResult } from '../types'; diff --git a/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/index.test.tsx index 26d9607a91fcd..9dc75e4c4534b 100644 --- a/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/open_timeline/timelines_table/index.test.tsx @@ -10,7 +10,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines/timelines_page'; +import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines'; import { mockTimelineResults } from '../../../mock/timeline_results'; import { OpenTimelineResult } from '../types'; import { TimelinesTable, TimelinesTableProps } from '.'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/first_last_seen_host/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/first_last_seen_host/index.test.tsx index 4a836333f3311..a378c007cf56f 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/first_last_seen_host/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/first_last_seen_host/index.test.tsx @@ -6,7 +6,7 @@ import { cloneDeep } from 'lodash/fp'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import { render, act } from '@testing-library/react'; import { mockFirstLastSeenHostQuery } from '../../../../containers/hosts/first_last_seen/mock'; @@ -19,16 +19,6 @@ describe('FirstLastSeen Component', () => { const firstSeen = 'Apr 8, 2019 @ 16:09:40.692'; const lastSeen = 'Apr 8, 2019 @ 18:35:45.064'; - // Suppress warnings about "react-apollo" until we migrate to apollo@3 - /* eslint-disable no-console */ - const originalError = console.error; - beforeAll(() => { - console.error = jest.fn(); - }); - afterAll(() => { - console.error = originalError; - }); - test('Loading', async () => { const { container } = render( diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/first_last_seen_host/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/first_last_seen_host/index.tsx index 70dff5eda5939..3c162c559fe2f 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/first_last_seen_host/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/first_last_seen_host/index.tsx @@ -6,7 +6,6 @@ import { EuiIcon, EuiLoadingSpinner, EuiText, EuiToolTip } from '@elastic/eui'; import React from 'react'; -import { ApolloConsumer } from 'react-apollo'; import { useFirstLastSeenHostQuery } from '../../../../containers/hosts/first_last_seen'; import { getEmptyTagValue } from '../../../empty_value'; @@ -19,44 +18,37 @@ export enum FirstLastSeenHostType { export const FirstLastSeenHost = React.memo<{ hostname: string; type: FirstLastSeenHostType }>( ({ hostname, type }) => { + const { loading, firstSeen, lastSeen, errorMessage } = useFirstLastSeenHostQuery( + hostname, + 'default' + ); + if (errorMessage != null) { + return ( + + + + ); + } + const valueSeen = type === FirstLastSeenHostType.FIRST_SEEN ? firstSeen : lastSeen; return ( - - {client => { - const { loading, firstSeen, lastSeen, errorMessage } = useFirstLastSeenHostQuery( - hostname, - 'default', - client - ); - if (errorMessage != null) { - return ( - - - - ); - } - const valueSeen = type === FirstLastSeenHostType.FIRST_SEEN ? firstSeen : lastSeen; - return ( - <> - {loading && } - {!loading && valueSeen != null && new Date(valueSeen).toString() === 'Invalid Date' - ? valueSeen - : !loading && - valueSeen != null && ( - - - - )} - {!loading && valueSeen == null && getEmptyTagValue()} - - ); - }} - + <> + {loading && } + {!loading && valueSeen != null && new Date(valueSeen).toString() === 'Invalid Date' + ? valueSeen + : !loading && + valueSeen != null && ( + + + + )} + {!loading && valueSeen == null && getEmptyTagValue()} + ); } ); diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/__snapshots__/index.test.tsx.snap index 3143e680913b2..1d70f4f72ac8b 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/__snapshots__/index.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/__snapshots__/index.test.tsx.snap @@ -68,97 +68,6 @@ exports[`Hosts Table rendering it renders the default Hosts table 1`] = ` } fakeTotalCount={50} id="hostsQuery" - indexPattern={ - Object { - "fields": Array [ - Object { - "aggregatable": true, - "name": "@timestamp", - "searchable": true, - "type": "date", - }, - Object { - "aggregatable": true, - "name": "@version", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "name": "agent.ephemeral_id", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "name": "agent.hostname", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "name": "agent.id", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "name": "agent.test1", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "name": "agent.test2", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "name": "agent.test3", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "name": "agent.test4", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "name": "agent.test5", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "name": "agent.test6", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "name": "agent.test7", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "name": "agent.test8", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "name": "host.name", - "searchable": true, - "type": "string", - }, - ], - "title": "filebeat-*,auditbeat-*,packetbeat-*", - } - } isInspect={false} loadPage={[MockFunction]} loading={false} diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/index.test.tsx index e561594013dea..cb70be5bc962c 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/index.test.tsx @@ -7,14 +7,9 @@ import { shallow } from 'enzyme'; import { getOr } from 'lodash/fp'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; -import { - apolloClientObservable, - mockIndexPattern, - mockGlobalState, - TestProviders, -} from '../../../../mock'; +import { apolloClientObservable, mockGlobalState, TestProviders } from '../../../../mock'; import { useMountAppended } from '../../../../utils/use_mount_appended'; import { createStore, hostsModel, State } from '../../../../store'; import { HostsTableType } from '../../../../store/hosts/model'; @@ -49,7 +44,6 @@ describe('Hosts Table', () => { data={mockData.Hosts.edges} id="hostsQuery" isInspect={false} - indexPattern={mockIndexPattern} fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.Hosts.pageInfo)} loading={false} loadPage={loadPage} @@ -72,7 +66,6 @@ describe('Hosts Table', () => { void; @@ -78,7 +75,6 @@ const HostsTableComponent = React.memo( direction, fakeTotalCount, id, - indexPattern, isInspect, limit, loading, diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.tsx index 65d5924821844..ae6c22afc53d7 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.tsx @@ -33,9 +33,7 @@ interface KpiHostDetailsProps extends GenericKpiHostProps { } const FlexGroupSpinner = styled(EuiFlexGroup)` - { - min-height: ${kpiWidgetHeight}px; - } + min-height: ${kpiWidgetHeight}px; `; FlexGroupSpinner.displayName = 'FlexGroupSpinner'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.test.tsx index e425057dd0f75..db0121298f2f9 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_dns_table/index.test.tsx @@ -7,7 +7,7 @@ import { shallow } from 'enzyme'; import { getOr } from 'lodash/fp'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import { Provider as ReduxStoreProvider } from 'react-redux'; import { apolloClientObservable, mockGlobalState, TestProviders } from '../../../../mock'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.test.tsx index c4596ada5c74d..e28cfa0ab6755 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.test.tsx @@ -7,7 +7,7 @@ import { shallow } from 'enzyme'; import { getOr } from 'lodash/fp'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import { Provider as ReduxStoreProvider } from 'react-redux'; import { apolloClientObservable, mockGlobalState, TestProviders } from '../../../../mock'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.test.tsx index 764e440a5a4be..f73c4e1a02f8f 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.test.tsx @@ -7,7 +7,7 @@ import { shallow } from 'enzyme'; import { getOr } from 'lodash/fp'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import { Provider as ReduxStoreProvider } from 'react-redux'; import { FlowTargetSourceDest } from '../../../../graphql/types'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.test.tsx index 78e8b15005f43..179ff4e2060bb 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.test.tsx @@ -7,7 +7,7 @@ import { shallow } from 'enzyme'; import { getOr } from 'lodash/fp'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import { Provider as ReduxStoreProvider } from 'react-redux'; import { FlowTargetSourceDest } from '../../../../graphql/types'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.test.tsx index 81a472f3175e5..bb35eb638fe55 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.test.tsx @@ -7,7 +7,7 @@ import { shallow } from 'enzyme'; import { getOr } from 'lodash/fp'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import { Provider as ReduxStoreProvider } from 'react-redux'; import { apolloClientObservable, mockGlobalState, TestProviders } from '../../../../mock'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.test.tsx index 8dc3704a089ea..b4b88fb48da8a 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.test.tsx @@ -7,7 +7,7 @@ import { shallow } from 'enzyme'; import { getOr } from 'lodash/fp'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import { Provider as ReduxStoreProvider } from 'react-redux'; import { FlowTarget } from '../../../../graphql/types'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.test.tsx index 568cf032fb01c..2167ddd7b78a3 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.test.tsx @@ -7,14 +7,13 @@ import { cloneDeep } from 'lodash/fp'; import { mount } from 'enzyme'; import React from 'react'; +import { MockedResponse, MockedProvider } from '@apollo/client/testing'; import { apolloClientObservable, mockGlobalState, TestProviders } from '../../../../mock'; import { OverviewHost } from '.'; import { createStore, State } from '../../../../store'; import { overviewHostQuery } from '../../../../containers/overview/overview_host/index.gql_query'; -import { GetOverviewHostQuery } from '../../../../graphql/types'; -import { MockedProvider } from 'react-apollo/test-utils'; import { wait } from '../../../../lib/helpers'; jest.mock('../../../../lib/kibana'); @@ -22,12 +21,7 @@ jest.mock('../../../../lib/kibana'); const startDate = 1579553397080; const endDate = 1579639797080; -interface MockedProvidedQuery { - request: { - query: GetOverviewHostQuery.Query; - fetchPolicy: string; - variables: GetOverviewHostQuery.Variables; - }; +interface MockedProvidedQuery extends MockedResponse { result: { data: { source: unknown; @@ -39,7 +33,6 @@ const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ { request: { query: overviewHostQuery, - fetchPolicy: 'cache-and-network', variables: { sourceId: 'default', timerange: { interval: '12h', from: startDate, to: endDate }, diff --git a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network/index.test.tsx index 151bb444cfe75..9cefddd3c41a2 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network/index.test.tsx @@ -7,14 +7,13 @@ import { cloneDeep } from 'lodash/fp'; import { mount } from 'enzyme'; import React from 'react'; +import { MockedProvider, MockedResponse } from '@apollo/client/testing'; import { apolloClientObservable, mockGlobalState, TestProviders } from '../../../../mock'; import { OverviewNetwork } from '.'; import { createStore, State } from '../../../../store'; import { overviewNetworkQuery } from '../../../../containers/overview/overview_network/index.gql_query'; -import { GetOverviewHostQuery } from '../../../../graphql/types'; -import { MockedProvider } from 'react-apollo/test-utils'; import { wait } from '../../../../lib/helpers'; jest.mock('../../../../lib/kibana'); @@ -22,12 +21,7 @@ jest.mock('../../../../lib/kibana'); const startDate = 1579553397080; const endDate = 1579639797080; -interface MockedProvidedQuery { - request: { - query: GetOverviewHostQuery.Query; - fetchPolicy: string; - variables: GetOverviewHostQuery.Variables; - }; +interface MockedProvidedQuery extends MockedResponse { result: { data: { source: unknown; @@ -39,7 +33,6 @@ const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ { request: { query: overviewNetworkQuery, - fetchPolicy: 'cache-and-network', variables: { sourceId: 'default', timerange: { interval: '12h', from: startDate, to: endDate }, diff --git a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network/index.tsx index 100abd997ee6b..8c6c96f6e233b 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_network/index.tsx @@ -50,6 +50,9 @@ const OverviewNetworkComponent: React.FC = ({ setQuery, }) => { const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); + const title = ( + + ); return ( @@ -89,12 +92,7 @@ const OverviewNetworkComponent: React.FC = ({ <>{''} ) } - title={ - - } + title={title} > ; filterBy: FilterMode; } export type Props = OwnProps & PropsFromRedux; const StatefulRecentTimelinesComponent = React.memo( - ({ apolloClient, filterBy, updateIsLoading, updateTimeline }) => { + ({ filterBy, updateIsLoading, updateTimeline }) => { + const apolloClient = useApolloClient(); const actionDispatcher = updateIsLoading as ActionCreator<{ id: string; isLoading: boolean }>; const onOpenTimeline: OnOpenTimeline = useCallback( ({ duplicate, timelineId }: { duplicate: boolean; timelineId: string }) => { diff --git a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx index 2513004af84dd..7f6c157fcabd6 100644 --- a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx @@ -372,7 +372,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ dispatch(inputsActions.setSearchBarFilter({ id, filters })), }); -export const connector = connect(makeMapStateToProps, mapDispatchToProps); +const connector = connect(makeMapStateToProps, mapDispatchToProps); type PropsFromRedux = ConnectedProps; diff --git a/x-pack/legacy/plugins/siem/public/components/stat_items/index.tsx b/x-pack/legacy/plugins/siem/public/components/stat_items/index.tsx index 3ebcba0a85a40..17a8e961836ce 100644 --- a/x-pack/legacy/plugins/siem/public/components/stat_items/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/stat_items/index.tsx @@ -18,7 +18,7 @@ import { get, getOr } from 'lodash/fp'; import React, { useState, useEffect } from 'react'; import styled from 'styled-components'; -import { KpiHostsData, KpiNetworkData } from '../../graphql/types'; +import { KpiHostsData, KpiHostDetailsData, KpiNetworkData } from '../../graphql/types'; import { AreaChart } from '../charts/areachart'; import { BarChart } from '../charts/barchart'; import { ChartSeriesData, ChartData, ChartSeriesConfigs, UpdateDateRange } from '../charts/common'; @@ -112,12 +112,12 @@ export const barchartConfigs = (config?: { onElementClick?: ElementClickListener export const addValueToFields = ( fields: StatItem[], - data: KpiHostsData | KpiNetworkData + data: KpiHostsData | KpiHostDetailsData | KpiNetworkData ): StatItem[] => fields.map(field => ({ ...field, value: get(field.key, data) })); export const addValueToAreaChart = ( fields: StatItem[], - data: KpiHostsData | KpiNetworkData + data: KpiHostsData | KpiHostDetailsData | KpiNetworkData ): ChartSeriesData[] => fields .filter(field => get(`${field.key}Histogram`, data) != null) @@ -129,7 +129,7 @@ export const addValueToAreaChart = ( export const addValueToBarChart = ( fields: StatItem[], - data: KpiHostsData | KpiNetworkData + data: KpiHostsData | KpiHostDetailsData | KpiNetworkData ): ChartSeriesData[] => { if (fields.length === 0) return []; return fields.reduce((acc: ChartSeriesData[], field: StatItem, idx: number) => { @@ -158,7 +158,7 @@ export const addValueToBarChart = ( export const useKpiMatrixStatus = ( mappings: Readonly, - data: KpiHostsData | KpiNetworkData, + data: KpiHostsData | KpiHostDetailsData | KpiNetworkData, id: string, from: number, to: number, diff --git a/x-pack/legacy/plugins/siem/public/components/super_date_picker/index.tsx b/x-pack/legacy/plugins/siem/public/components/super_date_picker/index.tsx index ad38a7d61bcba..ff79351271cca 100644 --- a/x-pack/legacy/plugins/siem/public/components/super_date_picker/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/super_date_picker/index.tsx @@ -306,7 +306,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ updateReduxTime: dispatchUpdateReduxTime(dispatch), }); -export const connector = connect(makeMapStateToProps, mapDispatchToProps); +const connector = connect(makeMapStateToProps, mapDispatchToProps); type PropsFromRedux = ConnectedProps; diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/body/helpers.test.ts b/x-pack/legacy/plugins/siem/public/components/timeline/body/helpers.test.ts index f021bf38b56c2..ced2f3f76f9f0 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/body/helpers.test.ts +++ b/x-pack/legacy/plugins/siem/public/components/timeline/body/helpers.test.ts @@ -11,7 +11,7 @@ import { eventHasNotes, eventIsPinned, getPinTooltip, stringifyEvent } from './h describe('helpers', () => { describe('stringifyEvent', () => { test('it omits __typename when it appears at arbitrary levels', () => { - const toStringify: Ecs = { + const toStringify: Ecs = ({ __typename: 'level 0', _id: '4', timestamp: '2018-11-08T19:03:25.937Z', @@ -54,7 +54,7 @@ describe('helpers', () => { region_name: ['neither'], country_iso_code: ['sasquatch'], }, - } as Ecs; // as cast so that `__typename` can be added for the tests even though it is not part of ECS + } as unknown) as Ecs; // as cast so that `__typename` can be added for the tests even though it is not part of ECS const expected: Ecs = { _id: '4', timestamp: '2018-11-08T19:03:25.937Z', diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/__snapshots__/zeek_details.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/__snapshots__/zeek_details.test.tsx.snap index 6b866aeecc831..e1b7de34e4004 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/__snapshots__/zeek_details.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/timeline/body/renderers/zeek/__snapshots__/zeek_details.test.tsx.snap @@ -1299,86 +1299,791 @@ tr:hover .c3:focus::before { ( return ( prevProps.browserFields === nextProps.browserFields && prevProps.columnHeaders === nextProps.columnHeaders && - prevProps.data === nextProps.data && + deepEqual(prevProps.data, nextProps.data) && prevProps.eventIdToNoteIds === nextProps.eventIdToNoteIds && prevProps.notesById === nextProps.notesById && prevProps.height === nextProps.height && diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/fetch_kql_timeline.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/fetch_kql_timeline.tsx index 65c539d77a16b..0689472cd5b96 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/fetch_kql_timeline.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/fetch_kql_timeline.tsx @@ -7,6 +7,7 @@ import { memo, useEffect } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { IIndexPattern } from 'src/plugins/data/public'; +import deepEqual from 'fast-deep-equal'; import { timelineSelectors, State } from '../../store'; import { inputsActions } from '../../store/actions'; @@ -39,7 +40,14 @@ const TimelineKqlFetchComponent = memo( }); }, [kueryFilterQueryDraft, kueryFilterQuery, id]); return null; - } + }, + (prevProps, nextProps) => + prevProps.id === nextProps.id && + deepEqual(prevProps.indexPattern, nextProps.indexPattern) && + prevProps.inputId === nextProps.inputId && + prevProps.kueryFilterQuery === nextProps.kueryFilterQuery && + prevProps.kueryFilterQueryDraft === nextProps.kueryFilterQueryDraft && + prevProps.setTimelineQuery === nextProps.setTimelineQuery ); const makeMapStateToProps = () => { @@ -58,7 +66,7 @@ const mapDispatchToProps = { setTimelineQuery: inputsActions.setQuery, }; -export const connector = connect(makeMapStateToProps, mapDispatchToProps); +const connector = connect(makeMapStateToProps, mapDispatchToProps); type PropsFromRedux = ConnectedProps; diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/footer/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/footer/index.tsx index 1fcc4382c1798..efcc6a2b71dc9 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/footer/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/footer/index.tsx @@ -177,7 +177,6 @@ interface FooterProps { getUpdatedAt: () => number; hasNextPage: boolean; height: number; - isEventViewer?: boolean; isLive: boolean; isLoading: boolean; itemsCount: number; @@ -196,7 +195,6 @@ export const FooterComponent = ({ getUpdatedAt, hasNextPage, height, - isEventViewer, isLive, isLoading, itemsCount, @@ -345,7 +343,6 @@ export const Footer = React.memo( prevProps.compact === nextProps.compact && prevProps.hasNextPage === nextProps.hasNextPage && prevProps.height === nextProps.height && - prevProps.isEventViewer === nextProps.isEventViewer && prevProps.isLive === nextProps.isLive && prevProps.isLoading === nextProps.isLoading && prevProps.itemsCount === nextProps.itemsCount && diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/header/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/header/index.tsx index 81eef0efbfa5b..bb9ee6efb9c78 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/header/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/header/index.tsx @@ -8,6 +8,7 @@ import { EuiCallOut } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; import { IIndexPattern } from 'src/plugins/data/public'; +import deepEqual from 'fast-deep-equal'; import { Sort } from '../body/sort'; import { DataProviders } from '../data_providers'; @@ -91,4 +92,19 @@ export const TimelineHeaderComponent: React.FC = ({ ); -export const TimelineHeader = React.memo(TimelineHeaderComponent); +export const TimelineHeader = React.memo( + TimelineHeaderComponent, + (prevProps, nextProps) => + deepEqual(prevProps.browserFields, nextProps.browserFields) && + prevProps.id === nextProps.id && + deepEqual(prevProps.indexPattern, nextProps.indexPattern) && + deepEqual(prevProps.dataProviders, nextProps.dataProviders) && + prevProps.onChangeDataProviderKqlQuery === nextProps.onChangeDataProviderKqlQuery && + prevProps.onChangeDroppableAndProvider === nextProps.onChangeDroppableAndProvider && + prevProps.onDataProviderEdited === nextProps.onDataProviderEdited && + prevProps.onDataProviderRemoved === nextProps.onDataProviderRemoved && + prevProps.onToggleDataProviderEnabled === nextProps.onToggleDataProviderEnabled && + prevProps.onToggleDataProviderExcluded === nextProps.onToggleDataProviderExcluded && + prevProps.show === nextProps.show && + prevProps.showCallOutUnauthorizedMsg === nextProps.showCallOutUnauthorizedMsg +); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/helpers.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/helpers.tsx index 611d08e61be22..c2a571d8086a7 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/helpers.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/helpers.tsx @@ -6,6 +6,7 @@ import { isEmpty, isNumber, get } from 'lodash/fp'; import memoizeOne from 'memoize-one'; +import deepEqual from 'fast-deep-equal'; import { escapeQueryValue, convertToBuildEsQuery } from '../../lib/keury'; @@ -93,65 +94,68 @@ export const buildGlobalQuery = (dataProviders: DataProvider[], browserFields: B }, '') .trim(); -export const combineQueries = ({ - config, - dataProviders, - indexPattern, - browserFields, - filters = [], - kqlQuery, - kqlMode, - start, - end, - isEventViewer, -}: { - config: EsQueryConfig; - dataProviders: DataProvider[]; - indexPattern: IIndexPattern; - browserFields: BrowserFields; - filters: Filter[]; - kqlQuery: Query; - kqlMode: string; - start: number; - end: number; - isEventViewer?: boolean; -}): { filterQuery: string } | null => { - const kuery: Query = { query: '', language: kqlQuery.language }; - if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters) && !isEventViewer) { - return null; - } else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEventViewer) { - kuery.query = `@timestamp >= ${start} and @timestamp <= ${end}`; - return { - filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }), - }; - } else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && !isEmpty(filters)) { - kuery.query = `@timestamp >= ${start} and @timestamp <= ${end}`; - return { - filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }), - }; - } else if (isEmpty(dataProviders) && !isEmpty(kqlQuery.query)) { - kuery.query = `(${kqlQuery.query}) and @timestamp >= ${start} and @timestamp <= ${end}`; - return { - filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }), - }; - } else if (!isEmpty(dataProviders) && isEmpty(kqlQuery)) { - kuery.query = `(${buildGlobalQuery( - dataProviders, - browserFields +export const combineQueries = memoizeOne( + ({ + config, + dataProviders, + indexPattern, + browserFields, + filters = [], + kqlQuery, + kqlMode, + start, + end, + isEventViewer, + }: { + config: EsQueryConfig; + dataProviders: DataProvider[]; + indexPattern: IIndexPattern; + browserFields: BrowserFields; + filters: Filter[]; + kqlQuery: Query; + kqlMode: string; + start: number; + end: number; + isEventViewer?: boolean; + }): { filterQuery: string } | null => { + const kuery: Query = { query: '', language: kqlQuery.language }; + if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters) && !isEventViewer) { + return null; + } else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEventViewer) { + kuery.query = `@timestamp >= ${start} and @timestamp <= ${end}`; + return { + filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }), + }; + } else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && !isEmpty(filters)) { + kuery.query = `@timestamp >= ${start} and @timestamp <= ${end}`; + return { + filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }), + }; + } else if (isEmpty(dataProviders) && !isEmpty(kqlQuery.query)) { + kuery.query = `(${kqlQuery.query}) and @timestamp >= ${start} and @timestamp <= ${end}`; + return { + filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }), + }; + } else if (!isEmpty(dataProviders) && isEmpty(kqlQuery)) { + kuery.query = `(${buildGlobalQuery( + dataProviders, + browserFields + )}) and @timestamp >= ${start} and @timestamp <= ${end}`; + return { + filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }), + }; + } + const operatorKqlQuery = kqlMode === 'filter' ? 'and' : 'or'; + const postpend = (q: string) => `${!isEmpty(q) ? ` ${operatorKqlQuery} (${q})` : ''}`; + kuery.query = `((${buildGlobalQuery(dataProviders, browserFields)})${postpend( + kqlQuery.query as string )}) and @timestamp >= ${start} and @timestamp <= ${end}`; return { filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }), }; - } - const operatorKqlQuery = kqlMode === 'filter' ? 'and' : 'or'; - const postpend = (q: string) => `${!isEmpty(q) ? ` ${operatorKqlQuery} (${q})` : ''}`; - kuery.query = `((${buildGlobalQuery(dataProviders, browserFields)})${postpend( - kqlQuery.query as string - )}) and @timestamp >= ${start} and @timestamp <= ${end}`; - return { - filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }), - }; -}; + }, + deepEqual +); interface CalculateBodyHeightParams { /** The the height of the flyout container, which is typically the entire "page", not including the standard Kibana navigation */ @@ -164,13 +168,15 @@ interface CalculateBodyHeightParams { timelineFooterHeight?: number; } -export const calculateBodyHeight = ({ - flyoutHeight = 0, - flyoutHeaderHeight = 0, - timelineHeaderHeight = 0, - timelineFooterHeight = 0, -}: CalculateBodyHeightParams): number => - flyoutHeight - (flyoutHeaderHeight + timelineHeaderHeight + timelineFooterHeight); +export const calculateBodyHeight = memoizeOne( + ({ + flyoutHeight = 0, + flyoutHeaderHeight = 0, + timelineHeaderHeight = 0, + timelineFooterHeight = 0, + }: CalculateBodyHeightParams): number => + flyoutHeight - (flyoutHeaderHeight + timelineHeaderHeight + timelineFooterHeight) +); /** * The CSS class name of a "stateful event", which appears in both diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx index 0ce6bc16f1325..24bf36b954afe 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/index.tsx @@ -8,7 +8,7 @@ import React, { useEffect, useCallback, useMemo } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import deepEqual from 'fast-deep-equal'; -import { WithSource } from '../../containers/source'; +import { useWithSource } from '../../containers/source'; import { useSignalIndex } from '../../containers/detection_engine/signals/use_signal_index'; import { inputsModel, inputsSelectors, State, timelineSelectors } from '../../store'; import { timelineActions } from '../../store/actions'; @@ -34,6 +34,8 @@ export interface OwnProps { type Props = OwnProps & PropsFromRedux; +const EMPTY_INDEX_TO_ADD: string[] = []; + const StatefulTimelineComponent = React.memo( ({ columns, @@ -75,7 +77,7 @@ const StatefulTimelineComponent = React.memo( ) { return [signalIndexName]; } - return []; + return EMPTY_INDEX_TO_ADD; }, [eventType, signalIndexExists, signalIndexName]); const onDataProviderRemoved: OnDataProviderRemoved = useCallback( @@ -163,42 +165,40 @@ const StatefulTimelineComponent = React.memo( } }, []); + const { indexPattern, browserFields } = useWithSource(indexToAdd); + return ( - - {({ indexPattern, browserFields }) => ( - - )} - + ); }, (prevProps, nextProps) => { diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/search_or_filter/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/search_or_filter/index.tsx index 87061bdbb5d02..614085d87c76e 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/search_or_filter/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/search_or_filter/index.tsx @@ -228,7 +228,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ updateReduxTime: dispatchUpdateReduxTime(dispatch), }); -export const connector = connect(makeMapStateToProps, mapDispatchToProps); +const connector = connect(makeMapStateToProps, mapDispatchToProps); type PropsFromRedux = ConnectedProps; diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/timeline.test.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/timeline.test.tsx index 4c5238d213e43..6bfb775496396 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/timeline.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/timeline.test.tsx @@ -6,7 +6,7 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; import useResizeObserver from 'use-resize-observer/polyfilled'; import { timelineQuery } from '../../containers/timeline/index.gql_query'; diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx index 58bbbef328ddf..fe6fad6ed0bca 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/timeline.tsx @@ -6,7 +6,7 @@ import { EuiFlexGroup } from '@elastic/eui'; import { getOr, isEmpty } from 'lodash/fp'; -import React from 'react'; +import React, { useMemo } from 'react'; import styled from 'styled-components'; import useResizeObserver from 'use-resize-observer/polyfilled'; @@ -121,6 +121,12 @@ export const TimelineComponent: React.FC = ({ const { ref: measureRef, width = 0, height: timelineHeaderHeight = 0 } = useResizeObserver< HTMLDivElement >({}); + const bodyHeight = calculateBodyHeight({ + flyoutHeight, + flyoutHeaderHeight, + timelineHeaderHeight, + timelineFooterHeight: footerHeight, + }); const kibana = useKibana(); const combinedQueries = combineQueries({ config: esQuery.getEsQueryConfig(kibana.services.uiSettings), @@ -133,7 +139,14 @@ export const TimelineComponent: React.FC = ({ start, end, }); - const columnsHeader = isEmpty(columns) ? defaultHeaders : columns; + const sortField = { + sortFieldId: sort.columnId, + direction: sort.sortDirection as Direction, + }; + const timelineQueryFields = useMemo(() => { + const columnsHeader = isEmpty(columns) ? defaultHeaders : columns; + return columnsHeader.map(c => c.id); + }, [columns]); return ( = ({ eventType={eventType} id={id} indexToAdd={indexToAdd} - fields={columnsHeader.map(c => c.id)} + fields={timelineQueryFields} sourceId="default" limit={itemsPerPage} filterQuery={combinedQueries.filterQuery} - sortField={{ - sortFieldId: sort.columnId, - direction: sort.sortDirection as Direction, - }} + sortField={sortField} > {({ events, @@ -196,12 +206,7 @@ export const TimelineComponent: React.FC = ({ browserFields={browserFields} data={events} id={id} - height={calculateBodyHeight({ - flyoutHeight, - flyoutHeaderHeight, - timelineHeaderHeight, - timelineFooterHeight: footerHeight, - })} + height={bodyHeight} sort={sort} toggleColumn={toggleColumn} /> diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/index.test.tsx index 10aa388449d91..879c7f4553bc6 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/url_state/index.test.tsx @@ -6,6 +6,7 @@ import { mount } from 'enzyme'; import React from 'react'; +import { MockedProvider } from '@apollo/client/testing'; import { HookWrapper } from '../../mock'; import { SiemPageName } from '../../pages/home/types'; @@ -72,7 +73,11 @@ describe('UrlStateContainer', () => { pageName, detailName, }).relativeTimeSearch.undefinedQuery; - mount( useUrlStateHooks(args)} />); + mount( + + useUrlStateHooks(args)} /> + + ); expect(mockSetRelativeRangeDatePicker.mock.calls[1][0]).toEqual({ from: 11223344556677, @@ -101,7 +106,11 @@ describe('UrlStateContainer', () => { (page, namespaceLower, namespaceUpper, examplePath, type, pageName, detailName) => { mockProps = getMockPropsObj({ page, examplePath, namespaceLower, pageName, detailName }) .absoluteTimeSearch.undefinedQuery; - mount( useUrlStateHooks(args)} />); + mount( + + useUrlStateHooks(args)} /> + + ); expect(mockSetAbsoluteRangeDatePicker.mock.calls[1][0]).toEqual({ from: 1556736012685, @@ -126,7 +135,11 @@ describe('UrlStateContainer', () => { (page, namespaceLower, namespaceUpper, examplePath, type, pageName, detailName) => { mockProps = getMockPropsObj({ page, examplePath, namespaceLower, pageName, detailName }) .relativeTimeSearch.undefinedQuery; - mount( useUrlStateHooks(args)} />); + mount( + + useUrlStateHooks(args)} /> + + ); expect(mockSetFilterQuery.mock.calls[0][0]).toEqual({ id: 'global', @@ -150,7 +163,11 @@ describe('UrlStateContainer', () => { pageName, detailName, }).noSearch.definedQuery; - mount( useUrlStateHooks(args)} />); + mount( + + useUrlStateHooks(args)} /> + + ); expect( mockHistory.replace.mock.calls[mockHistory.replace.mock.calls.length - 1][0] @@ -180,7 +197,9 @@ describe('UrlStateContainer', () => { detailName, }).relativeTimeSearch.undefinedQuery; const wrapper = mount( - useUrlStateHooks(args)} /> + + useUrlStateHooks(args)} /> + ); wrapper.setProps({ diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx index 294e41a1faa7b..362a398999393 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx @@ -52,4 +52,4 @@ const UseUrlStateComponent: React.FC = props => { return ; }; -export const UseUrlState = React.memo(UseUrlStateComponent); +export const UseUrlState = React.memo(UseUrlStateComponent, deepEqual); diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/index_mocked.test.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/index_mocked.test.tsx index 4adc17b32e189..60c253dcaf936 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/index_mocked.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/url_state/index_mocked.test.tsx @@ -6,6 +6,7 @@ import { mount } from 'enzyme'; import React from 'react'; +import { MockedProvider } from '@apollo/client/testing'; import { HookWrapper } from '../../mock/hook_wrapper'; import { SiemPageName } from '../../pages/home/types'; @@ -46,7 +47,8 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () => detailName: undefined, }).noSearch.definedQuery; const wrapper = mount( - useUrlStateHooks(args)} /> + useUrlStateHooks(args)} />, + { wrappingComponent: MockedProvider } ); const newUrlState = { @@ -97,7 +99,8 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () => detailName: undefined, }).noSearch.undefinedQuery; const wrapper = mount( - useUrlStateHooks(args)} /> + useUrlStateHooks(args)} />, + { wrappingComponent: MockedProvider } ); const newUrlState = { ...mockProps.urlState, @@ -129,7 +132,8 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () => }).noSearch.undefinedQuery; const wrapper = mount( - useUrlStateHooks(args)} /> + useUrlStateHooks(args)} />, + { wrappingComponent: MockedProvider } ); const newUrlState = { ...mockProps.urlState, @@ -161,7 +165,9 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () => (page, namespaceLower, namespaceUpper, examplePath, type, pageName, detailName) => { mockProps = getMockPropsObj({ page, examplePath, namespaceLower, pageName, detailName }) .noSearch.undefinedQuery; - mount( useUrlStateHooks(args)} />); + mount( useUrlStateHooks(args)} />, { + wrappingComponent: MockedProvider, + }); expect(mockHistory.replace.mock.calls[0][0]).toEqual({ hash: '', @@ -198,7 +204,8 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () => detailName: undefined, }).noSearch.definedQuery; const wrapper = mount( - useUrlStateHooks(args)} /> + useUrlStateHooks(args)} />, + { wrappingComponent: MockedProvider } ); expect( diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/types.ts b/x-pack/legacy/plugins/siem/public/components/url_state/types.ts index 2cb1b0c96ad79..ebd18cdd31732 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/types.ts +++ b/x-pack/legacy/plugins/siem/public/components/url_state/types.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import ApolloClient from 'apollo-client'; +import { ApolloClient } from '@apollo/client'; import * as H from 'history'; import { ActionCreator } from 'typescript-fsa'; import { @@ -88,9 +88,6 @@ export type KeyUrlState = keyof UrlState; export interface UrlStateProps { navTabs: Record; indexPattern?: IIndexPattern; - mapToUrlState?: (value: string) => UrlState; - onChange?: (urlState: UrlState, previousUrlState: UrlState) => void; - onInitialize?: (urlState: UrlState) => void; } export interface UrlStateStateToPropsType { diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx index a7704e0e86970..9d4d42e681a75 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx +++ b/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx @@ -6,10 +6,10 @@ import { difference, isEmpty } from 'lodash/fp'; import { useEffect, useRef, useState } from 'react'; +import { useApolloClient } from '@apollo/client'; import deepEqual from 'fast-deep-equal'; import { useKibana } from '../../lib/kibana'; -import { useApolloClient } from '../../utils/apollo_context'; import { CONSTANTS, UrlStateType } from './constants'; import { getQueryStringFromLocation, diff --git a/x-pack/legacy/plugins/siem/public/containers/authentications/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/authentications/index.gql_query.ts index eee35730cfdbb..1e0b080af4cf1 100644 --- a/x-pack/legacy/plugins/siem/public/containers/authentications/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/authentications/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const authenticationsQuery = gql` query GetAuthenticationsQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/authentications/index.tsx b/x-pack/legacy/plugins/siem/public/containers/authentications/index.tsx index 6d4a88c45a768..5ada3f171e96c 100644 --- a/x-pack/legacy/plugins/siem/public/containers/authentications/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/authentications/index.tsx @@ -6,7 +6,6 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect } from 'react-redux'; import { compose } from 'redux'; @@ -14,6 +13,7 @@ import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { AuthenticationsEdges, GetAuthenticationsQuery, + GetAuthenticationsQueryComponent, PageInfoPaginated, } from '../../graphql/types'; import { hostsModel, hostsSelectors, inputsModel, State, inputsSelectors } from '../../store'; @@ -22,8 +22,6 @@ import { generateTablePaginationOptions } from '../../components/paginated_table import { withKibana, WithKibanaProps } from '../../lib/kibana'; import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated'; -import { authenticationsQuery } from './index.gql_query'; - const ID = 'authenticationQuery'; export interface AuthenticationArgs { @@ -39,7 +37,7 @@ export interface AuthenticationArgs { } export interface OwnProps extends QueryTemplatePaginatedProps { - children: (args: AuthenticationArgs) => React.ReactNode; + children: (args: AuthenticationArgs) => React.ReactElement; type: hostsModel.HostsType; } @@ -83,8 +81,7 @@ class AuthenticationsComponentQuery extends QueryTemplatePaginated< inspect: isInspected, }; return ( - - query={authenticationsQuery} + + ); } } diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/fetch_index_patterns.test.tsx b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/fetch_index_patterns.test.tsx index cad78ac565903..bf5e60847a045 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/fetch_index_patterns.test.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/fetch_index_patterns.test.tsx @@ -5,15 +5,15 @@ */ import { renderHook, act } from '@testing-library/react-hooks'; +import { useApolloClient } from '@apollo/client'; import { defaultIndexPattern } from '../../../../default_index_pattern'; -import { useApolloClient } from '../../../utils/apollo_context'; import { mocksSource } from '../../source/mock'; import { useFetchIndexPatterns, Return } from './fetch_index_patterns'; const mockUseApolloClient = useApolloClient as jest.Mock; -jest.mock('../../../utils/apollo_context'); +jest.mock('@apollo/client'); describe('useFetchIndexPatterns', () => { beforeEach(() => { diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/fetch_index_patterns.tsx b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/fetch_index_patterns.tsx index 06c4d1054bca4..1aee0e4c36807 100644 --- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/fetch_index_patterns.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/fetch_index_patterns.tsx @@ -6,6 +6,7 @@ import { isEmpty, get } from 'lodash/fp'; import { useEffect, useState, Dispatch, SetStateAction } from 'react'; +import { useApolloClient } from '@apollo/client'; import deepEqual from 'fast-deep-equal'; import { IIndexPattern } from '../../../../../../../../src/plugins/data/public'; @@ -18,7 +19,6 @@ import { import { useStateToaster } from '../../../components/toasters'; import { errorToToaster } from '../../../components/ml/api/error_to_toaster'; import { SourceQuery } from '../../../graphql/types'; -import { useApolloClient } from '../../../utils/apollo_context'; import * as i18n from './translations'; diff --git a/x-pack/legacy/plugins/siem/public/containers/errors/index.test.tsx b/x-pack/legacy/plugins/siem/public/containers/errors/index.test.tsx index e1b192df104d7..81ccb76c83fb5 100644 --- a/x-pack/legacy/plugins/siem/public/containers/errors/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/errors/index.test.tsx @@ -5,8 +5,7 @@ */ import { reTryOneTimeOnErrorHandler, errorLinkHandler } from '.'; -import { ServerError } from 'apollo-link-http-common'; -import { Operation } from 'apollo-link'; +import { ServerError, Operation } from '@apollo/client'; import { GraphQLError } from 'graphql'; import * as store from '../../store'; import { onError } from 'apollo-link-error'; diff --git a/x-pack/legacy/plugins/siem/public/containers/events/last_event_time/index.ts b/x-pack/legacy/plugins/siem/public/containers/events/last_event_time/index.ts index 9cae503d30940..b4ec108c69922 100644 --- a/x-pack/legacy/plugins/siem/public/containers/events/last_event_time/index.ts +++ b/x-pack/legacy/plugins/siem/public/containers/events/last_event_time/index.ts @@ -5,16 +5,18 @@ */ import { get } from 'lodash/fp'; -import React, { useEffect, useState } from 'react'; +import { FetchPolicy } from '@apollo/client'; import { DEFAULT_INDEX_KEY } from '../../../../common/constants'; -import { GetLastEventTimeQuery, LastEventIndexKey, LastTimeDetails } from '../../../graphql/types'; +import { + LastEventIndexKey, + LastTimeDetails, + useGetLastEventTimeQueryQuery, +} from '../../../graphql/types'; import { inputsModel } from '../../../store'; -import { QueryTemplateProps } from '../../query_template'; import { useUiSetting$ } from '../../../lib/kibana'; import { LastEventTimeGqlQuery } from './last_event_time.gql_query'; -import { useApolloClient } from '../../../utils/apollo_context'; export interface LastEventTimeArgs { id: string; @@ -24,63 +26,29 @@ export interface LastEventTimeArgs { refetch: inputsModel.Refetch; } -export interface OwnProps extends QueryTemplateProps { - children: (args: LastEventTimeArgs) => React.ReactNode; - indexKey: LastEventIndexKey; -} - -export function useLastEventTimeQuery( +export const useLastEventTimeQuery = ( indexKey: LastEventIndexKey, details: LastTimeDetails, sourceId: string -) { - const [loading, updateLoading] = useState(false); - const [lastSeen, updateLastSeen] = useState(null); - const [errorMessage, updateErrorMessage] = useState(null); - const [currentIndexKey, updateCurrentIndexKey] = useState(null); +) => { const [defaultIndex] = useUiSetting$(DEFAULT_INDEX_KEY); - const apolloClient = useApolloClient(); - async function fetchLastEventTime(signal: AbortSignal) { - updateLoading(true); - if (apolloClient) { - apolloClient - .query({ - query: LastEventTimeGqlQuery, - fetchPolicy: 'cache-first', - variables: { - sourceId, - indexKey, - details, - defaultIndex, - }, - context: { - fetchOptions: { - signal, - }, - }, - }) - .then( - result => { - updateLoading(false); - updateLastSeen(get('data.source.LastEventTime.lastSeen', result)); - updateErrorMessage(null); - updateCurrentIndexKey(currentIndexKey); - }, - error => { - updateLoading(false); - updateLastSeen(null); - updateErrorMessage(error.message); - } - ); - } - } - - useEffect(() => { - const abortCtrl = new AbortController(); - const signal = abortCtrl.signal; - fetchLastEventTime(signal); - return () => abortCtrl.abort(); - }, [apolloClient, indexKey, details.hostName, details.ip]); - - return { lastSeen, loading, errorMessage }; -} + const options = { + query: LastEventTimeGqlQuery, + fetchPolicy: 'cache-first' as FetchPolicy, + variables: { + sourceId, + indexKey, + details, + defaultIndex, + }, + }; + + const { data, loading, error } = useGetLastEventTimeQueryQuery(options); + const lastSeen = get('source.LastEventTime.lastSeen', data); + + return { + lastSeen, + loading, + errorMessage: error?.message, + }; +}; diff --git a/x-pack/legacy/plugins/siem/public/containers/events/last_event_time/last_event_time.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/events/last_event_time/last_event_time.gql_query.ts index 049c73b607b7e..22f56014cfb46 100644 --- a/x-pack/legacy/plugins/siem/public/containers/events/last_event_time/last_event_time.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/events/last_event_time/last_event_time.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const LastEventTimeGqlQuery = gql` query GetLastEventTimeQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/events/last_event_time/mock.ts b/x-pack/legacy/plugins/siem/public/containers/events/last_event_time/mock.ts index ca8786077851f..5e7f473b87748 100644 --- a/x-pack/legacy/plugins/siem/public/containers/events/last_event_time/mock.ts +++ b/x-pack/legacy/plugins/siem/public/containers/events/last_event_time/mock.ts @@ -4,16 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ +import { MockedResponse } from '@apollo/client/testing'; + import { defaultIndexPattern } from '../../../../default_index_pattern'; -import { GetLastEventTimeQuery, LastEventIndexKey } from '../../../graphql/types'; +import { LastEventIndexKey } from '../../../graphql/types'; import { LastEventTimeGqlQuery } from './last_event_time.gql_query'; -interface MockLastEventTimeQuery { - request: { - query: GetLastEventTimeQuery.Query; - variables: GetLastEventTimeQuery.Variables; - }; +interface MockLastEventTimeQuery extends MockedResponse { result: { data?: { source: { @@ -24,7 +22,6 @@ interface MockLastEventTimeQuery { }; }; }; - errors?: [{ message: string }]; }; } diff --git a/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx b/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx index 4632e9aee3fdd..14cdc65ee7bb0 100644 --- a/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/global_time/index.tsx @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useCallback, useState, useEffect } from 'react'; -import { connect, ConnectedProps } from 'react-redux'; +import { useCallback, useState, useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; -import { inputsModel, inputsSelectors, State } from '../../store'; +import { inputsModel, inputsSelectors } from '../../store'; import { inputsActions } from '../../store/actions'; interface SetQuery { @@ -25,31 +25,24 @@ export interface GlobalTimeArgs { isInitializing: boolean; } -interface OwnProps { - children: (args: GlobalTimeArgs) => React.ReactNode; -} - -type GlobalTimeProps = OwnProps & PropsFromRedux; - -export const GlobalTimeComponent: React.FC = ({ - children, - deleteAllQuery, - deleteOneQuery, - from, - to, - setGlobalQuery, -}) => { +export const useGlobalTime = () => { const [isInitializing, setIsInitializing] = useState(true); + const dispatch = useDispatch(); + const { from, to } = useSelector(inputsSelectors.globalTimeRangeSelector); + + const deleteAllQuery = useCallback(props => dispatch(inputsActions.deleteAllQuery(props)), [ + dispatch, + ]); const setQuery = useCallback( ({ id, inspect, loading, refetch }: SetQuery) => - setGlobalQuery({ inputId: 'global', id, inspect, loading, refetch }), - [setGlobalQuery] + dispatch(inputsActions.setQuery({ inputId: 'global', id, inspect, loading, refetch })), + [dispatch] ); const deleteQuery = useCallback( - ({ id }: { id: string }) => deleteOneQuery({ inputId: 'global', id }), - [deleteOneQuery] + ({ id }: { id: string }) => dispatch(inputsActions.deleteOneQuery({ inputId: 'global', id })), + [dispatch] ); useEffect(() => { @@ -59,37 +52,13 @@ export const GlobalTimeComponent: React.FC = ({ return () => { deleteAllQuery({ id: 'global' }); }; - }, []); - - return ( - <> - {children({ - isInitializing, - from, - to, - setQuery, - deleteQuery, - })} - - ); -}; + }, [isInitializing, deleteAllQuery]); -const mapStateToProps = (state: State) => { - const timerange: inputsModel.TimeRange = inputsSelectors.globalTimeRangeSelector(state); return { - from: timerange.from, - to: timerange.to, + isInitializing, + from, + to, + setQuery, + deleteQuery, }; }; - -const mapDispatchToProps = { - deleteAllQuery: inputsActions.deleteAllQuery, - deleteOneQuery: inputsActions.deleteOneQuery, - setGlobalQuery: inputsActions.setQuery, -}; - -export const connector = connect(mapStateToProps, mapDispatchToProps); - -type PropsFromRedux = ConnectedProps; - -export const GlobalTime = connector(React.memo(GlobalTimeComponent)); diff --git a/x-pack/legacy/plugins/siem/public/containers/helpers.ts b/x-pack/legacy/plugins/siem/public/containers/helpers.ts index 5f66e3f4b88d4..a43c1c066db73 100644 --- a/x-pack/legacy/plugins/siem/public/containers/helpers.ts +++ b/x-pack/legacy/plugins/siem/public/containers/helpers.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { FetchPolicy } from 'apollo-client'; +import { WatchQueryFetchPolicy } from '@apollo/client'; import { isString } from 'lodash/fp'; import { ESQuery } from '../../common/typed_json'; @@ -12,4 +12,4 @@ import { ESQuery } from '../../common/typed_json'; export const createFilter = (filterQuery: ESQuery | string | undefined) => isString(filterQuery) ? filterQuery : JSON.stringify(filterQuery); -export const getDefaultFetchPolicy = (): FetchPolicy => 'cache-and-network'; +export const getDefaultFetchPolicy = (): WatchQueryFetchPolicy => 'cache-and-network'; diff --git a/x-pack/legacy/plugins/siem/public/containers/hosts/first_last_seen/first_last_seen.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/hosts/first_last_seen/first_last_seen.gql_query.ts index 7db4f138c7794..1a794bb53bdf7 100644 --- a/x-pack/legacy/plugins/siem/public/containers/hosts/first_last_seen/first_last_seen.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/hosts/first_last_seen/first_last_seen.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const HostFirstLastSeenGqlQuery = gql` query GetHostFirstLastSeenQuery($sourceId: ID!, $hostName: String!, $defaultIndex: [String!]!) { diff --git a/x-pack/legacy/plugins/siem/public/containers/hosts/first_last_seen/index.ts b/x-pack/legacy/plugins/siem/public/containers/hosts/first_last_seen/index.ts index e36da5bfbe4ee..2fb60ebce86f7 100644 --- a/x-pack/legacy/plugins/siem/public/containers/hosts/first_last_seen/index.ts +++ b/x-pack/legacy/plugins/siem/public/containers/hosts/first_last_seen/index.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import ApolloClient from 'apollo-client'; +import { useApolloClient } from '@apollo/client'; import { get } from 'lodash/fp'; import React, { useEffect, useState } from 'react'; @@ -26,19 +26,16 @@ export interface FirstLastSeenHostArgs { } export interface OwnProps extends QueryTemplateProps { - children: (args: FirstLastSeenHostArgs) => React.ReactNode; + children: (args: FirstLastSeenHostArgs) => React.ReactElement; hostName: string; } -export function useFirstLastSeenHostQuery( - hostName: string, - sourceId: string, - apolloClient: ApolloClient -) { +export function useFirstLastSeenHostQuery(hostName: string, sourceId: string) { const [loading, updateLoading] = useState(false); const [firstSeen, updateFirstSeen] = useState(null); const [lastSeen, updateLastSeen] = useState(null); const [errorMessage, updateErrorMessage] = useState(null); + const apolloClient = useApolloClient(); const [defaultIndex] = useUiSetting$(DEFAULT_INDEX_KEY); async function fetchFirstLastSeenHost(signal: AbortSignal) { diff --git a/x-pack/legacy/plugins/siem/public/containers/hosts/first_last_seen/mock.ts b/x-pack/legacy/plugins/siem/public/containers/hosts/first_last_seen/mock.ts index 2c9d418763e8e..22080c7a86101 100644 --- a/x-pack/legacy/plugins/siem/public/containers/hosts/first_last_seen/mock.ts +++ b/x-pack/legacy/plugins/siem/public/containers/hosts/first_last_seen/mock.ts @@ -4,16 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ +import { MockedResponse } from '@apollo/client/testing'; import { defaultIndexPattern } from '../../../../default_index_pattern'; -import { GetHostFirstLastSeenQuery } from '../../../graphql/types'; import { HostFirstLastSeenGqlQuery } from './first_last_seen.gql_query'; -interface MockedProvidedQuery { - request: { - query: GetHostFirstLastSeenQuery.Query; - variables: GetHostFirstLastSeenQuery.Variables; - }; +interface MockedProvidedQuery extends MockedResponse { result: { data?: { source: { @@ -24,9 +20,9 @@ interface MockedProvidedQuery { }; }; }; - errors?: [{ message: string }]; }; } + export const mockFirstLastSeenHostQuery: MockedProvidedQuery[] = [ { request: { diff --git a/x-pack/legacy/plugins/siem/public/containers/hosts/hosts_table.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/hosts/hosts_table.gql_query.ts index 672ea70b09ad2..555d4ede5bfcd 100644 --- a/x-pack/legacy/plugins/siem/public/containers/hosts/hosts_table.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/hosts/hosts_table.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const HostsTableQuery = gql` query GetHostsTableQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/hosts/index.tsx b/x-pack/legacy/plugins/siem/public/containers/hosts/index.tsx index 733c2224d840a..ccd51534ec794 100644 --- a/x-pack/legacy/plugins/siem/public/containers/hosts/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/hosts/index.tsx @@ -7,7 +7,6 @@ import { get, getOr } from 'lodash/fp'; import memoizeOne from 'memoize-one'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect } from 'react-redux'; import { compose } from 'redux'; @@ -15,6 +14,7 @@ import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { Direction, GetHostsTableQuery, + GetHostsTableQueryComponent, HostsEdges, HostsFields, PageInfoPaginated, @@ -24,7 +24,6 @@ import { createFilter, getDefaultFetchPolicy } from '../helpers'; import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated'; import { withKibana, WithKibanaProps } from '../../lib/kibana'; -import { HostsTableQuery } from './hosts_table.gql_query'; import { generateTablePaginationOptions } from '../../components/paginated_table/helpers'; const ID = 'hostsQuery'; @@ -44,7 +43,7 @@ export interface HostsArgs { } export interface OwnProps extends QueryTemplatePaginatedProps { - children: (args: HostsArgs) => React.ReactNode; + children: (args: HostsArgs) => React.ReactElement; type: hostsModel.HostsType; startDate: number; endDate: number; @@ -110,8 +109,7 @@ class HostsComponentQuery extends QueryTemplatePaginated< inspect: isInspected, }; return ( - - query={HostsTableQuery} + + ); } diff --git a/x-pack/legacy/plugins/siem/public/containers/hosts/overview/host_overview.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/hosts/overview/host_overview.gql_query.ts index 46794816dbf2a..7427352b49523 100644 --- a/x-pack/legacy/plugins/siem/public/containers/hosts/overview/host_overview.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/hosts/overview/host_overview.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const HostOverviewQuery = gql` query GetHostOverviewQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/hosts/overview/index.tsx b/x-pack/legacy/plugins/siem/public/containers/hosts/overview/index.tsx index 5057e872b5313..14e2591f5650b 100644 --- a/x-pack/legacy/plugins/siem/public/containers/hosts/overview/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/hosts/overview/index.tsx @@ -6,7 +6,6 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect } from 'react-redux'; import { compose } from 'redux'; @@ -16,8 +15,11 @@ import { getDefaultFetchPolicy } from '../../helpers'; import { QueryTemplate, QueryTemplateProps } from '../../query_template'; import { withKibana, WithKibanaProps } from '../../../lib/kibana'; -import { HostOverviewQuery } from './host_overview.gql_query'; -import { GetHostOverviewQuery, HostItem } from '../../../graphql/types'; +import { + GetHostOverviewQuery, + GetHostOverviewQueryComponent, + HostItem, +} from '../../../graphql/types'; const ID = 'hostOverviewQuery'; @@ -36,7 +38,7 @@ export interface HostOverviewReduxProps { } export interface OwnProps extends QueryTemplateProps { - children: (args: HostOverviewArgs) => React.ReactNode; + children: (args: HostOverviewArgs) => React.ReactElement; hostName: string; startDate: number; endDate: number; @@ -62,8 +64,7 @@ class HostOverviewByNameComponentQuery extends QueryTemplate< endDate, } = this.props; return ( - - query={HostOverviewQuery} + + ); } } diff --git a/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.gql_query.ts index 3733cd780a4f7..875413f4cac0d 100644 --- a/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const ipOverviewQuery = gql` query GetIpOverviewQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.tsx b/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.tsx index ade94c430c6ef..9d83af620b730 100644 --- a/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.tsx @@ -6,18 +6,15 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect, ConnectedProps } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; -import { GetIpOverviewQuery, IpOverviewData } from '../../graphql/types'; +import { GetIpOverviewQueryComponent, IpOverviewData } from '../../graphql/types'; import { networkModel, inputsModel, inputsSelectors, State } from '../../store'; import { useUiSetting } from '../../lib/kibana'; import { createFilter, getDefaultFetchPolicy } from '../helpers'; import { QueryTemplateProps } from '../query_template'; -import { ipOverviewQuery } from './index.gql_query'; - const ID = 'ipOverviewQuery'; export interface IpOverviewArgs { @@ -29,15 +26,14 @@ export interface IpOverviewArgs { } export interface IpOverviewProps extends QueryTemplateProps { - children: (args: IpOverviewArgs) => React.ReactNode; + children: (args: IpOverviewArgs) => React.ReactElement; type: networkModel.NetworkType; ip: string; } const IpOverviewComponentQuery = React.memo( ({ id = ID, isInspected, children, filterQuery, skip, sourceId, ip }) => ( - - query={ipOverviewQuery} + ( refetch, }); }} - + ) ); diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.gql_query.tsx b/x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.gql_query.ts similarity index 97% rename from x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.gql_query.tsx rename to x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.gql_query.ts index 077f49c4bdfa6..3b847d1b71560 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.gql_query.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const kpiHostDetailsQuery = gql` fragment KpiHostDetailsChartFields on KpiHostHistogramData { diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.tsx index de9d54b1a185c..1568cf60586d7 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kpi_host_details/index.tsx @@ -6,18 +6,15 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect, ConnectedProps } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; -import { KpiHostDetailsData, GetKpiHostDetailsQuery } from '../../graphql/types'; +import { KpiHostDetailsData, GetKpiHostDetailsQueryComponent } from '../../graphql/types'; import { inputsModel, inputsSelectors, State } from '../../store'; import { useUiSetting } from '../../lib/kibana'; import { createFilter, getDefaultFetchPolicy } from '../helpers'; import { QueryTemplateProps } from '../query_template'; -import { kpiHostDetailsQuery } from './index.gql_query'; - const ID = 'kpiHostDetailsQuery'; export interface KpiHostDetailsArgs { @@ -29,13 +26,12 @@ export interface KpiHostDetailsArgs { } export interface QueryKpiHostDetailsProps extends QueryTemplateProps { - children: (args: KpiHostDetailsArgs) => React.ReactNode; + children: (args: KpiHostDetailsArgs) => React.ReactElement; } const KpiHostDetailsComponentQuery = React.memo( ({ id = ID, children, endDate, filterQuery, isInspected, skip, sourceId, startDate }) => ( - - query={kpiHostDetailsQuery} + + ) ); diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.gql_query.ts index 37d54455db1fd..e359adf2a354f 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const kpiHostsQuery = gql` fragment KpiHostChartFields on KpiHostHistogramData { diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx index 5be2423e8a162..543a2b6035b81 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx @@ -6,18 +6,15 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect, ConnectedProps } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; -import { GetKpiHostsQuery, KpiHostsData } from '../../graphql/types'; +import { GetKpiHostsQueryComponent, KpiHostsData } from '../../graphql/types'; import { inputsModel, inputsSelectors, State } from '../../store'; import { useUiSetting } from '../../lib/kibana'; import { createFilter, getDefaultFetchPolicy } from '../helpers'; import { QueryTemplateProps } from '../query_template'; -import { kpiHostsQuery } from './index.gql_query'; - const ID = 'kpiHostsQuery'; export interface KpiHostsArgs { @@ -29,13 +26,12 @@ export interface KpiHostsArgs { } export interface KpiHostsProps extends QueryTemplateProps { - children: (args: KpiHostsArgs) => React.ReactNode; + children: (args: KpiHostsArgs) => React.ReactElement; } const KpiHostsComponentQuery = React.memo( ({ id = ID, children, endDate, filterQuery, isInspected, skip, sourceId, startDate }) => ( - - query={kpiHostsQuery} + ( refetch, }); }} - + ) ); diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.gql_query.ts index 3c693f08b45f2..90f773fad229c 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const kpiNetworkQuery = gql` fragment KpiNetworkChartFields on KpiNetworkHistogramData { diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx index 338cdc39b178c..019cc718fd5be 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx @@ -6,18 +6,15 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect, ConnectedProps } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; -import { GetKpiNetworkQuery, KpiNetworkData } from '../../graphql/types'; +import { GetKpiNetworkQueryComponent, KpiNetworkData } from '../../graphql/types'; import { inputsModel, inputsSelectors, State } from '../../store'; import { useUiSetting } from '../../lib/kibana'; import { createFilter, getDefaultFetchPolicy } from '../helpers'; import { QueryTemplateProps } from '../query_template'; -import { kpiNetworkQuery } from './index.gql_query'; - const ID = 'kpiNetworkQuery'; export interface KpiNetworkArgs { @@ -29,13 +26,12 @@ export interface KpiNetworkArgs { } export interface KpiNetworkProps extends QueryTemplateProps { - children: (args: KpiNetworkArgs) => React.ReactNode; + children: (args: KpiNetworkArgs) => React.ReactElement; } const KpiNetworkComponentQuery = React.memo( ({ id = ID, children, filterQuery, isInspected, skip, sourceId, startDate, endDate }) => ( - - query={kpiNetworkQuery} + ( refetch, }); }} - + ) ); diff --git a/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.gql_query.ts index 6fb729ca7e9a0..8c032c17a6b95 100644 --- a/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const MatrixHistogramGqlQuery = gql` query GetMatrixHistogramQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.test.tsx b/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.test.tsx index 06367ab8657a8..141d986c5188b 100644 --- a/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.test.tsx @@ -7,7 +7,8 @@ import { useQuery } from '.'; import { mount } from 'enzyme'; import React from 'react'; -import { useApolloClient } from '../../utils/apollo_context'; +import { useApolloClient } from '@apollo/client'; + import { errorToToaster } from '../../components/ml/api/error_to_toaster'; import { MatrixOverTimeHistogramData, HistogramType } from '../../graphql/types'; import { InspectQuery, Refetch } from '../../store/inputs/model'; @@ -25,7 +26,7 @@ const mockQuery = jest.fn().mockResolvedValue({ }); const mockRejectQuery = jest.fn().mockRejectedValue(new Error()); -jest.mock('../../utils/apollo_context', () => ({ +jest.mock('@apollo/client', () => ({ useApolloClient: jest.fn(), })); diff --git a/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.ts b/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.ts index 683d5b68c305b..c995e5065a3ec 100644 --- a/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.ts +++ b/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.ts @@ -4,13 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ import { useEffect, useState, useRef } from 'react'; +import { useApolloClient } from '@apollo/client'; + import { MatrixHistogramQueryProps } from '../../components/matrix_histogram/types'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { useStateToaster } from '../../components/toasters'; import { errorToToaster } from '../../components/ml/api/error_to_toaster'; import { useUiSetting$ } from '../../lib/kibana'; import { createFilter } from '../helpers'; -import { useApolloClient } from '../../utils/apollo_context'; import { inputsModel } from '../../store'; import { MatrixHistogramGqlQuery } from './index.gql_query'; import { GetMatrixHistogramQuery, MatrixOverTimeHistogramData } from '../../graphql/types'; diff --git a/x-pack/legacy/plugins/siem/public/containers/network_dns/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/network_dns/index.gql_query.ts index a81d112fa4c50..ad272466d2370 100644 --- a/x-pack/legacy/plugins/siem/public/containers/network_dns/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/network_dns/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const networkDnsQuery = gql` query GetNetworkDnsQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/network_dns/index.tsx b/x-pack/legacy/plugins/siem/public/containers/network_dns/index.tsx index 04c8783c30a0f..da6aeb34d33c6 100644 --- a/x-pack/legacy/plugins/siem/public/containers/network_dns/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/network_dns/index.tsx @@ -6,7 +6,6 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect } from 'react-redux'; import { compose } from 'redux'; @@ -15,6 +14,7 @@ import { ScaleType } from '@elastic/charts'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { GetNetworkDnsQuery, + GetNetworkDnsQueryComponent, NetworkDnsEdges, NetworkDnsSortField, PageInfoPaginated, @@ -25,7 +25,6 @@ import { withKibana, WithKibanaProps } from '../../lib/kibana'; import { generateTablePaginationOptions } from '../../components/paginated_table/helpers'; import { createFilter, getDefaultFetchPolicy } from '../helpers'; import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated'; -import { networkDnsQuery } from './index.gql_query'; import { DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from '../../store/constants'; import { MatrixHistogram } from '../../components/matrix_histogram'; import { MatrixHistogramOption, GetSubTitle } from '../../components/matrix_histogram/types'; @@ -49,7 +48,7 @@ export interface NetworkDnsArgs { } export interface OwnProps extends QueryTemplatePaginatedProps { - children: (args: NetworkDnsArgs) => React.ReactNode; + children: (args: NetworkDnsArgs) => React.ReactElement; type: networkModel.NetworkType; } @@ -117,10 +116,9 @@ export class NetworkDnsComponentQuery extends QueryTemplatePaginated< }; return ( - + @@ -161,7 +159,7 @@ export class NetworkDnsComponentQuery extends QueryTemplatePaginated< histogram: getOr(null, 'source.NetworkDns.histogram', data), }); }} - + ); } } diff --git a/x-pack/legacy/plugins/siem/public/containers/network_http/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/network_http/index.gql_query.ts index bedf13dfa9849..b084fe846dca2 100644 --- a/x-pack/legacy/plugins/siem/public/containers/network_http/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/network_http/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const networkHttpQuery = gql` query GetNetworkHttpQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/network_http/index.tsx b/x-pack/legacy/plugins/siem/public/containers/network_http/index.tsx index bf4e64f63d559..1f0759d25e870 100644 --- a/x-pack/legacy/plugins/siem/public/containers/network_http/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/network_http/index.tsx @@ -6,13 +6,13 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect } from 'react-redux'; import { compose } from 'redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { GetNetworkHttpQuery, + GetNetworkHttpQueryComponent, NetworkHttpEdges, NetworkHttpSortField, PageInfoPaginated, @@ -22,7 +22,6 @@ import { withKibana, WithKibanaProps } from '../../lib/kibana'; import { generateTablePaginationOptions } from '../../components/paginated_table/helpers'; import { createFilter, getDefaultFetchPolicy } from '../helpers'; import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated'; -import { networkHttpQuery } from './index.gql_query'; const ID = 'networkHttpQuery'; @@ -40,7 +39,7 @@ export interface NetworkHttpArgs { } export interface OwnProps extends QueryTemplatePaginatedProps { - children: (args: NetworkHttpArgs) => React.ReactNode; + children: (args: NetworkHttpArgs) => React.ReactElement; ip?: string; type: networkModel.NetworkType; } @@ -90,10 +89,9 @@ class NetworkHttpComponentQuery extends QueryTemplatePaginated< }, }; return ( - + @@ -133,7 +131,7 @@ class NetworkHttpComponentQuery extends QueryTemplatePaginated< totalCount: getOr(-1, 'source.NetworkHttp.totalCount', data), }); }} - + ); } } diff --git a/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.gql_query.ts index 5850246ceecec..4c647d910ebd6 100644 --- a/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const networkTopCountriesQuery = gql` query GetNetworkTopCountriesQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.tsx b/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.tsx index bd1e1a002bbcd..43f3616b79924 100644 --- a/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.tsx @@ -6,7 +6,6 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect } from 'react-redux'; import { compose } from 'redux'; @@ -14,6 +13,7 @@ import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { FlowTargetSourceDest, GetNetworkTopCountriesQuery, + GetNetworkTopCountriesQueryComponent, NetworkTopCountriesEdges, NetworkTopTablesSortField, PageInfoPaginated, @@ -23,7 +23,6 @@ import { withKibana, WithKibanaProps } from '../../lib/kibana'; import { generateTablePaginationOptions } from '../../components/paginated_table/helpers'; import { createFilter, getDefaultFetchPolicy } from '../helpers'; import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated'; -import { networkTopCountriesQuery } from './index.gql_query'; const ID = 'networkTopCountriesQuery'; @@ -41,7 +40,7 @@ export interface NetworkTopCountriesArgs { } export interface OwnProps extends QueryTemplatePaginatedProps { - children: (args: NetworkTopCountriesArgs) => React.ReactNode; + children: (args: NetworkTopCountriesArgs) => React.ReactElement; flowTarget: FlowTargetSourceDest; ip?: string; type: networkModel.NetworkType; @@ -94,10 +93,9 @@ class NetworkTopCountriesComponentQuery extends QueryTemplatePaginated< }, }; return ( - + @@ -137,7 +135,7 @@ class NetworkTopCountriesComponentQuery extends QueryTemplatePaginated< totalCount: getOr(-1, 'source.NetworkTopCountries.totalCount', data), }); }} - + ); } } diff --git a/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.gql_query.ts index a73f9ff9256ff..ba852e042016c 100644 --- a/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const networkTopNFlowQuery = gql` query GetNetworkTopNFlowQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.tsx b/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.tsx index f0f1f8257f29f..3121ab9d8433c 100644 --- a/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.tsx @@ -6,7 +6,6 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect } from 'react-redux'; import { compose } from 'redux'; @@ -14,6 +13,7 @@ import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { FlowTargetSourceDest, GetNetworkTopNFlowQuery, + GetNetworkTopNFlowQueryComponent, NetworkTopNFlowEdges, NetworkTopTablesSortField, PageInfoPaginated, @@ -23,7 +23,6 @@ import { inputsModel, inputsSelectors, networkModel, networkSelectors, State } f import { generateTablePaginationOptions } from '../../components/paginated_table/helpers'; import { createFilter, getDefaultFetchPolicy } from '../helpers'; import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated'; -import { networkTopNFlowQuery } from './index.gql_query'; const ID = 'networkTopNFlowQuery'; @@ -41,7 +40,7 @@ export interface NetworkTopNFlowArgs { } export interface OwnProps extends QueryTemplatePaginatedProps { - children: (args: NetworkTopNFlowArgs) => React.ReactNode; + children: (args: NetworkTopNFlowArgs) => React.ReactElement; flowTarget: FlowTargetSourceDest; ip?: string; type: networkModel.NetworkType; @@ -94,10 +93,9 @@ class NetworkTopNFlowComponentQuery extends QueryTemplatePaginated< }, }; return ( - + @@ -137,7 +135,7 @@ class NetworkTopNFlowComponentQuery extends QueryTemplatePaginated< totalCount: getOr(-1, 'source.NetworkTopNFlow.totalCount', data), }); }} - + ); } } diff --git a/x-pack/legacy/plugins/siem/public/containers/overview/overview_host/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/overview/overview_host/index.gql_query.ts index 6f17bf6915aa4..a1b6998ec2e75 100644 --- a/x-pack/legacy/plugins/siem/public/containers/overview/overview_host/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/overview/overview_host/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const overviewHostQuery = gql` query GetOverviewHostQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/overview/overview_host/index.tsx b/x-pack/legacy/plugins/siem/public/containers/overview/overview_host/index.tsx index 2dd9ccf24d802..8d7028e3f6bd7 100644 --- a/x-pack/legacy/plugins/siem/public/containers/overview/overview_host/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/overview/overview_host/index.tsx @@ -6,19 +6,16 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect, ConnectedProps } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../../common/constants'; -import { GetOverviewHostQuery, OverviewHostData } from '../../../graphql/types'; +import { GetOverviewHostQueryComponent, OverviewHostData } from '../../../graphql/types'; import { useUiSetting } from '../../../lib/kibana'; import { inputsModel, inputsSelectors } from '../../../store/inputs'; import { State } from '../../../store'; import { createFilter, getDefaultFetchPolicy } from '../../helpers'; import { QueryTemplateProps } from '../../query_template'; -import { overviewHostQuery } from './index.gql_query'; - export const ID = 'overviewHostQuery'; export interface OverviewHostArgs { @@ -30,43 +27,40 @@ export interface OverviewHostArgs { } export interface OverviewHostProps extends QueryTemplateProps { - children: (args: OverviewHostArgs) => React.ReactNode; + children: (args: OverviewHostArgs) => React.ReactElement; sourceId: string; endDate: number; startDate: number; } const OverviewHostComponentQuery = React.memo( - ({ id = ID, children, filterQuery, isInspected, sourceId, startDate, endDate }) => { - return ( - - query={overviewHostQuery} - fetchPolicy={getDefaultFetchPolicy()} - variables={{ - sourceId, - timerange: { - interval: '12h', - from: startDate, - to: endDate, - }, - filterQuery: createFilter(filterQuery), - defaultIndex: useUiSetting(DEFAULT_INDEX_KEY), - inspect: isInspected, - }} - > - {({ data, loading, refetch }) => { - const overviewHost = getOr({}, `source.OverviewHost`, data); - return children({ - id, - inspect: getOr(null, 'source.OverviewHost.inspect', data), - overviewHost, - loading, - refetch, - }); - }} - - ); - } + ({ id = ID, children, filterQuery, isInspected, sourceId, startDate, endDate }) => ( + (DEFAULT_INDEX_KEY), + inspect: isInspected, + }} + > + {({ data, loading, refetch }) => { + const overviewHost = getOr({}, `source.OverviewHost`, data); + return children({ + id, + inspect: getOr(null, 'source.OverviewHost.inspect', data), + overviewHost, + loading, + refetch, + }); + }} + + ) ); OverviewHostComponentQuery.displayName = 'OverviewHostComponentQuery'; diff --git a/x-pack/legacy/plugins/siem/public/containers/overview/overview_network/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/overview/overview_network/index.gql_query.ts index d40ab900b91a7..6eb8dc9dcdaec 100644 --- a/x-pack/legacy/plugins/siem/public/containers/overview/overview_network/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/overview/overview_network/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const overviewNetworkQuery = gql` query GetOverviewNetworkQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/overview/overview_network/index.tsx b/x-pack/legacy/plugins/siem/public/containers/overview/overview_network/index.tsx index d0acd41c224a5..5ae8741c2545e 100644 --- a/x-pack/legacy/plugins/siem/public/containers/overview/overview_network/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/overview/overview_network/index.tsx @@ -6,19 +6,16 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect, ConnectedProps } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../../common/constants'; -import { GetOverviewNetworkQuery, OverviewNetworkData } from '../../../graphql/types'; +import { GetOverviewNetworkQueryComponent, OverviewNetworkData } from '../../../graphql/types'; import { useUiSetting } from '../../../lib/kibana'; import { State } from '../../../store'; import { inputsModel, inputsSelectors } from '../../../store/inputs'; import { createFilter, getDefaultFetchPolicy } from '../../helpers'; import { QueryTemplateProps } from '../../query_template'; -import { overviewNetworkQuery } from './index.gql_query'; - export const ID = 'overviewNetworkQuery'; export interface OverviewNetworkArgs { @@ -30,7 +27,7 @@ export interface OverviewNetworkArgs { } export interface OverviewNetworkProps extends QueryTemplateProps { - children: (args: OverviewNetworkArgs) => React.ReactNode; + children: (args: OverviewNetworkArgs) => React.ReactElement; sourceId: string; endDate: number; startDate: number; @@ -38,8 +35,7 @@ export interface OverviewNetworkProps extends QueryTemplateProps { export const OverviewNetworkComponentQuery = React.memo( ({ id = ID, children, filterQuery, isInspected, sourceId, startDate, endDate }) => ( - - query={overviewNetworkQuery} + + ) ); diff --git a/x-pack/legacy/plugins/siem/public/containers/query_template.tsx b/x-pack/legacy/plugins/siem/public/containers/query_template.tsx index dfb452c24b86e..43b9237bf0cb7 100644 --- a/x-pack/legacy/plugins/siem/public/containers/query_template.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/query_template.tsx @@ -4,9 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ApolloQueryResult } from 'apollo-client'; +import { + ApolloQueryResult, + FetchMoreOptions, + FetchMoreQueryOptions, + OperationVariables, +} from '@apollo/client'; import React from 'react'; -import { FetchMoreOptions, FetchMoreQueryOptions, OperationVariables } from 'react-apollo'; import { ESQuery } from '../../common/typed_json'; diff --git a/x-pack/legacy/plugins/siem/public/containers/query_template_paginated.tsx b/x-pack/legacy/plugins/siem/public/containers/query_template_paginated.tsx index db618f216d83e..c01289bf61f6c 100644 --- a/x-pack/legacy/plugins/siem/public/containers/query_template_paginated.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/query_template_paginated.tsx @@ -4,10 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ApolloQueryResult, NetworkStatus } from 'apollo-client'; -import memoizeOne from 'memoize-one'; +import { + ApolloQueryResult, + NetworkStatus, + FetchMoreOptions, + FetchMoreQueryOptions, + OperationVariables, +} from '@apollo/client'; import React from 'react'; -import { FetchMoreOptions, FetchMoreQueryOptions, OperationVariables } from 'react-apollo'; +import memoizeOne from 'memoize-one'; import deepEqual from 'fast-deep-equal'; import { ESQuery } from '../../common/typed_json'; diff --git a/x-pack/legacy/plugins/siem/public/containers/source/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/source/index.gql_query.ts index 1f9ba09167e1e..6c84ee7f29c41 100644 --- a/x-pack/legacy/plugins/siem/public/containers/source/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/source/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const sourceQuery = gql` query SourceQuery($sourceId: ID = "default", $defaultIndex: [String!]!) { diff --git a/x-pack/legacy/plugins/siem/public/containers/source/index.test.tsx b/x-pack/legacy/plugins/siem/public/containers/source/index.test.tsx index d1a183a402e37..d64a7ebab44f4 100644 --- a/x-pack/legacy/plugins/siem/public/containers/source/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/source/index.test.tsx @@ -4,55 +4,39 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEqual } from 'lodash/fp'; -import { mount } from 'enzyme'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { MockedProvider } from '@apollo/client/testing'; +import { renderHook } from '@testing-library/react-hooks'; -import { wait } from '../../lib/helpers'; - -import { WithSource, indicesExistOrDataTemporarilyUnavailable } from '.'; +import { useWithSource, indicesExistOrDataTemporarilyUnavailable } from '.'; import { mockBrowserFields, mockIndexFields, mocksSource } from './mock'; jest.mock('../../lib/kibana'); describe('Index Fields & Browser Fields', () => { test('Index Fields', async () => { - mount( + const wrapper: React.ComponentType = ({ children }) => ( - - {({ indexPattern }) => { - if (!isEqual(indexPattern.fields, [])) { - expect(indexPattern.fields).toEqual(mockIndexFields); - } - - return null; - }} - + {(children as unknown) as undefined} ); + const { result, waitForNextUpdate } = renderHook(() => useWithSource(), { wrapper }); - // Why => https://github.com/apollographql/react-apollo/issues/1711 - await wait(); + await waitForNextUpdate(); + + expect(result.current.indexPattern.fields).toEqual(mockIndexFields); }); test('Browser Fields', async () => { - mount( + const wrapper: React.ComponentType = ({ children }) => ( - - {({ browserFields }) => { - if (!isEqual(browserFields, {})) { - expect(browserFields).toEqual(mockBrowserFields); - } - - return null; - }} - + {(children as unknown) as undefined} ); + const { result, waitForNextUpdate } = renderHook(() => useWithSource(), { wrapper }); + await waitForNextUpdate(); - // Why => https://github.com/apollographql/react-apollo/issues/1711 - await wait(); + expect(result.current.browserFields).toEqual(mockBrowserFields); }); describe('indicesExistOrDataTemporarilyUnavailable', () => { diff --git a/x-pack/legacy/plugins/siem/public/containers/source/index.tsx b/x-pack/legacy/plugins/siem/public/containers/source/index.tsx index e454421ca955d..f8f85f0fccc04 100644 --- a/x-pack/legacy/plugins/siem/public/containers/source/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/source/index.tsx @@ -6,18 +6,16 @@ import { isUndefined } from 'lodash'; import { get, keyBy, pick, set, isEmpty } from 'lodash/fp'; -import { Query } from 'react-apollo'; -import React, { useEffect, useMemo, useState } from 'react'; +import { useMemo } from 'react'; import memoizeOne from 'memoize-one'; import { IIndexPattern } from 'src/plugins/data/public'; import { useUiSetting$ } from '../../lib/kibana'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; -import { IndexField, SourceQuery } from '../../graphql/types'; +import { IndexField, useSourceQueryQuery } from '../../graphql/types'; import { sourceQuery } from './index.gql_query'; -import { useApolloClient } from '../../utils/apollo_context'; export { sourceQuery }; @@ -50,18 +48,6 @@ export const getAllFieldsByName = ( ): { [fieldName: string]: Partial } => keyBy('name', getAllBrowserFields(browserFields)); -interface WithSourceArgs { - indicesExist: boolean; - browserFields: BrowserFields; - indexPattern: IIndexPattern; -} - -interface WithSourceProps { - children: (args: WithSourceArgs) => React.ReactNode; - indexToAdd?: string[] | null; - sourceId: string; -} - export const getIndexFields = memoizeOne( (title: string, fields: IndexField[]): IIndexPattern => fields && fields.length > 0 @@ -83,7 +69,10 @@ export const getBrowserFields = memoizeOne( : {} ); -export const WithSource = React.memo(({ children, indexToAdd, sourceId }) => { +export const indicesExistOrDataTemporarilyUnavailable = (indicesExist: boolean | undefined) => + indicesExist || isUndefined(indicesExist); + +export const useWithSource = (indexToAdd?: string[] | null, sourceId: string = 'default') => { const [configIndex] = useUiSetting$(DEFAULT_INDEX_KEY); const defaultIndex = useMemo(() => { if (indexToAdd != null && !isEmpty(indexToAdd)) { @@ -92,86 +81,28 @@ export const WithSource = React.memo(({ children, indexToAdd, s return configIndex; }, [configIndex, indexToAdd]); - return ( - - query={sourceQuery} - fetchPolicy="cache-first" - notifyOnNetworkStatusChange - variables={{ - sourceId, - defaultIndex, - }} - > - {({ data }) => - children({ - indicesExist: get('source.status.indicesExist', data), - browserFields: getBrowserFields( - defaultIndex.join(), - get('source.status.indexFields', data) - ), - indexPattern: getIndexFields(defaultIndex.join(), get('source.status.indexFields', data)), - }) - } - + const variables = { + sourceId, + defaultIndex, + }; + + const { data } = useSourceQueryQuery({ + fetchPolicy: 'cache-first', + notifyOnNetworkStatusChange: true, + variables, + }); + + const indicesExist = get('source.status.indicesExist', data); + const browserFields = getBrowserFields( + defaultIndex.join(), + get('source.status.indexFields', data) ); -}); - -WithSource.displayName = 'WithSource'; - -export const indicesExistOrDataTemporarilyUnavailable = (indicesExist: boolean | undefined) => - indicesExist || isUndefined(indicesExist); - -export const useWithSource = (sourceId: string, indices: string[]) => { - const [loading, updateLoading] = useState(false); - const [indicesExist, setIndicesExist] = useState(undefined); - const [browserFields, setBrowserFields] = useState(null); - const [indexPattern, setIndexPattern] = useState(null); - const [errorMessage, updateErrorMessage] = useState(null); - - const apolloClient = useApolloClient(); - async function fetchSource(signal: AbortSignal) { - updateLoading(true); - if (apolloClient) { - apolloClient - .query({ - query: sourceQuery, - fetchPolicy: 'cache-first', - variables: { - sourceId, - defaultIndex: indices, - }, - context: { - fetchOptions: { - signal, - }, - }, - }) - .then( - result => { - updateLoading(false); - updateErrorMessage(null); - setIndicesExist(get('data.source.status.indicesExist', result)); - setBrowserFields( - getBrowserFields(indices.join(), get('data.source.status.indexFields', result)) - ); - setIndexPattern( - getIndexFields(indices.join(), get('data.source.status.indexFields', result)) - ); - }, - error => { - updateLoading(false); - updateErrorMessage(error.message); - } - ); - } - } - - useEffect(() => { - const abortCtrl = new AbortController(); - const signal = abortCtrl.signal; - fetchSource(signal); - return () => abortCtrl.abort(); - }, [apolloClient, sourceId, indices]); - - return { indicesExist, browserFields, indexPattern, loading, errorMessage }; + const indexPattern = getIndexFields(defaultIndex.join(), get('source.status.indexFields', data)); + const contentAvailable = indicesExistOrDataTemporarilyUnavailable(indicesExist); + + return { + browserFields, + indexPattern, + contentAvailable, + }; }; diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/all/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/timeline/all/index.gql_query.ts index e380e46e77070..055c7203ef78e 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/all/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/all/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const allTimelinesQuery = gql` query GetAllTimeline( diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/all/index.tsx b/x-pack/legacy/plugins/siem/public/containers/timeline/all/index.tsx index 22c7b03f34dd5..1da4404146a44 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/all/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/all/index.tsx @@ -8,16 +8,14 @@ import { getOr } from 'lodash/fp'; import React from 'react'; import memoizeOne from 'memoize-one'; -import { Query } from 'react-apollo'; - import { OpenTimelineResult } from '../../../components/open_timeline/types'; import { GetAllTimeline, + GetAllTimelineComponent, PageInfoTimeline, SortTimeline, TimelineResult, } from '../../../graphql/types'; -import { allTimelinesQuery } from './index.gql_query'; export interface AllTimelinesArgs { timelines: OpenTimelineResult[]; @@ -33,7 +31,7 @@ export interface AllTimelinesVariables { } interface OwnProps extends AllTimelinesVariables { - children?: (args: AllTimelinesArgs) => React.ReactNode; + children?: (args: AllTimelinesArgs) => React.ReactElement; } const getAllTimeline = memoizeOne( @@ -85,8 +83,7 @@ const AllTimelinesQueryComponent: React.FC = ({ sort, }; return ( - - query={allTimelinesQuery} + = ({ ), }) } - + ); }; diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/delete/persist.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/timeline/delete/persist.gql_query.ts index 4096d7245e89b..1cdd4a4c66c32 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/delete/persist.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/delete/persist.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const deleteTimelineMutation = gql` mutation DeleteTimelineMutation($id: [ID!]!) { diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/details/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/timeline/details/index.gql_query.ts index 4677d2328be87..2618fe8565536 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/details/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/details/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const timelineDetailsQuery = gql` query GetTimelineDetailsQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/details/index.tsx b/x-pack/legacy/plugins/siem/public/containers/timeline/details/index.tsx index cf1b8954307e7..4c5e0f7940449 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/details/index.tsx @@ -7,14 +7,15 @@ import { getOr } from 'lodash/fp'; import memoizeOne from 'memoize-one'; import React from 'react'; -import { Query } from 'react-apollo'; import { DEFAULT_INDEX_KEY } from '../../../../common/constants'; -import { DetailItem, GetTimelineDetailsQuery } from '../../../graphql/types'; +import { + DetailItem, + GetTimelineDetailsQuery, + GetTimelineDetailsQueryComponent, +} from '../../../graphql/types'; import { useUiSetting } from '../../../lib/kibana'; -import { timelineDetailsQuery } from './index.gql_query'; - export interface EventsArgs { detailsData: DetailItem[] | null; loading: boolean; @@ -46,8 +47,7 @@ const TimelineDetailsQueryComponent: React.FC = ({ defaultIndex: useUiSetting(DEFAULT_INDEX_KEY), }; return executeQuery ? ( - - query={timelineDetailsQuery} + = ({ ), }) } - + ) : ( children!({ loading: false, detailsData: null }) ); diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/favorite/persist.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/timeline/favorite/persist.gql_query.ts index 27d3fdd342e19..d11c87df8332f 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/favorite/persist.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/favorite/persist.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const persistTimelineFavoriteMutation = gql` mutation PersistTimelineFavoriteMutation($timelineId: ID) { diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/timeline/index.gql_query.ts index c54238c5d8687..3d9026085f7f5 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const timelineQuery = gql` query GetTimelineQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/index.tsx b/x-pack/legacy/plugins/siem/public/containers/timeline/index.tsx index ccd8babd41e68..5ee36f3a75f98 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/index.tsx @@ -7,7 +7,6 @@ import { getOr } from 'lodash/fp'; import memoizeOne from 'memoize-one'; import React from 'react'; -import { Query } from 'react-apollo'; import { compose, Dispatch } from 'redux'; import { connect, ConnectedProps } from 'react-redux'; @@ -15,6 +14,7 @@ import { IIndexPattern } from '../../../../../../../src/plugins/data/common/inde import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { GetTimelineQuery, + GetTimelineQueryComponent, PageInfo, SortField, TimelineEdges, @@ -25,7 +25,6 @@ import { withKibana, WithKibanaProps } from '../../lib/kibana'; import { createFilter } from '../helpers'; import { QueryTemplate, QueryTemplateProps } from '../query_template'; import { EventType } from '../../store/timeline/model'; -import { timelineQuery } from './index.gql_query'; import { timelineActions } from '../../store/timeline'; import { SIGNALS_PAGE_TIMELINE_ID } from '../../pages/detection_engine/components/signals'; @@ -41,12 +40,8 @@ export interface TimelineArgs { getUpdatedAt: () => number; } -export interface CustomReduxProps { - clearSignalsState: ({ id }: { id?: string }) => void; -} - export interface OwnProps extends QueryTemplateProps { - children?: (args: TimelineArgs) => React.ReactNode; + children?: (args: TimelineArgs) => React.ReactElement; eventType?: EventType; id: string; indexPattern?: IIndexPattern; @@ -56,7 +51,7 @@ export interface OwnProps extends QueryTemplateProps { fields: string[]; } -type TimelineQueryProps = OwnProps & PropsFromRedux & WithKibanaProps & CustomReduxProps; +type TimelineQueryProps = OwnProps & PropsFromRedux & WithKibanaProps; class TimelineQueryComponent extends QueryTemplate< TimelineQueryProps, @@ -106,8 +101,7 @@ class TimelineQueryComponent extends QueryTemplate< }; return ( - - query={timelineQuery} + + ); } diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/notes/persist.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/timeline/notes/persist.gql_query.ts index ff9ea164acee4..fbb3c4cd8b3f7 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/notes/persist.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/notes/persist.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const persistTimelineNoteMutation = gql` mutation PersistTimelineNoteMutation($noteId: ID, $version: String, $note: NoteInput!) { diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/one/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/timeline/one/index.gql_query.ts index e68db445a5cbb..8e5af210ddfd4 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/one/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/one/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const oneTimelineQuery = gql` query GetOneTimeline($id: ID!) { diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/persist.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/timeline/persist.gql_query.ts index 6a0609f9158f3..787a8027e5fef 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/persist.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/persist.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const persistTimelineMutation = gql` mutation PersistTimelineMutation($timelineId: ID, $version: String, $timeline: TimelineInput!) { diff --git a/x-pack/legacy/plugins/siem/public/containers/timeline/pinned_event/persist.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/timeline/pinned_event/persist.gql_query.ts index 7257dcb404011..d66dc4fb28a00 100644 --- a/x-pack/legacy/plugins/siem/public/containers/timeline/pinned_event/persist.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/timeline/pinned_event/persist.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const persistTimelinePinnedEventMutation = gql` mutation PersistTimelinePinnedEventMutation($pinnedEventId: ID, $eventId: ID!, $timelineId: ID) { diff --git a/x-pack/legacy/plugins/siem/public/containers/tls/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/tls/index.gql_query.ts index bbb92282bee83..68b79adcbcf55 100644 --- a/x-pack/legacy/plugins/siem/public/containers/tls/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/tls/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const tlsQuery = gql` query GetTlsQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/tls/index.tsx b/x-pack/legacy/plugins/siem/public/containers/tls/index.tsx index 3738355c8846e..77aa79c29fb81 100644 --- a/x-pack/legacy/plugins/siem/public/containers/tls/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/tls/index.tsx @@ -6,7 +6,6 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect } from 'react-redux'; import { compose } from 'redux'; @@ -16,6 +15,7 @@ import { TlsEdges, TlsSortField, GetTlsQuery, + GetTlsQueryComponent, FlowTargetSourceDest, } from '../../graphql/types'; import { inputsModel, networkModel, networkSelectors, State, inputsSelectors } from '../../store'; @@ -23,7 +23,6 @@ import { withKibana, WithKibanaProps } from '../../lib/kibana'; import { createFilter, getDefaultFetchPolicy } from '../helpers'; import { generateTablePaginationOptions } from '../../components/paginated_table/helpers'; import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated'; -import { tlsQuery } from './index.gql_query'; const ID = 'tlsQuery'; @@ -40,7 +39,7 @@ export interface TlsArgs { } export interface OwnProps extends QueryTemplatePaginatedProps { - children: (args: TlsArgs) => React.ReactNode; + children: (args: TlsArgs) => React.ReactElement; flowTarget: FlowTargetSourceDest; ip: string; type: networkModel.NetworkType; @@ -93,8 +92,7 @@ class TlsComponentQuery extends QueryTemplatePaginated< }, }; return ( - - query={tlsQuery} + + ); } } diff --git a/x-pack/legacy/plugins/siem/public/containers/uncommon_processes/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/uncommon_processes/index.gql_query.ts index d984de020faa1..6ab980e338e32 100644 --- a/x-pack/legacy/plugins/siem/public/containers/uncommon_processes/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/uncommon_processes/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const uncommonProcessesQuery = gql` query GetUncommonProcessesQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/uncommon_processes/index.tsx b/x-pack/legacy/plugins/siem/public/containers/uncommon_processes/index.tsx index 0a2ce67d9be80..06b6306bd1140 100644 --- a/x-pack/legacy/plugins/siem/public/containers/uncommon_processes/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/uncommon_processes/index.tsx @@ -6,13 +6,13 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect, ConnectedProps } from 'react-redux'; import { compose } from 'redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; import { GetUncommonProcessesQuery, + GetUncommonProcessesQueryComponent, PageInfoPaginated, UncommonProcessesEdges, } from '../../graphql/types'; @@ -22,8 +22,6 @@ import { generateTablePaginationOptions } from '../../components/paginated_table import { createFilter, getDefaultFetchPolicy } from '../helpers'; import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated'; -import { uncommonProcessesQuery } from './index.gql_query'; - const ID = 'uncommonProcessesQuery'; export interface UncommonProcessesArgs { @@ -39,7 +37,7 @@ export interface UncommonProcessesArgs { } export interface OwnProps extends QueryTemplatePaginatedProps { - children: (args: UncommonProcessesArgs) => React.ReactNode; + children: (args: UncommonProcessesArgs) => React.ReactElement; type: hostsModel.HostsType; } @@ -77,8 +75,7 @@ class UncommonProcessesComponentQuery extends QueryTemplatePaginated< }, }; return ( - - query={uncommonProcessesQuery} + + ); } } diff --git a/x-pack/legacy/plugins/siem/public/containers/users/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/users/index.gql_query.ts index 3fc1cdfd160db..a1ddff1a60e64 100644 --- a/x-pack/legacy/plugins/siem/public/containers/users/index.gql_query.ts +++ b/x-pack/legacy/plugins/siem/public/containers/users/index.gql_query.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const usersQuery = gql` query GetUsersQuery( diff --git a/x-pack/legacy/plugins/siem/public/containers/users/index.tsx b/x-pack/legacy/plugins/siem/public/containers/users/index.tsx index 5f71449c52460..f1e0351ef2fe3 100644 --- a/x-pack/legacy/plugins/siem/public/containers/users/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/users/index.tsx @@ -6,20 +6,23 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { Query } from 'react-apollo'; import { connect, ConnectedProps } from 'react-redux'; import { compose } from 'redux'; import { DEFAULT_INDEX_KEY } from '../../../common/constants'; -import { GetUsersQuery, FlowTarget, PageInfoPaginated, UsersEdges } from '../../graphql/types'; +import { + GetUsersQuery, + FlowTarget, + PageInfoPaginated, + UsersEdges, + GetUsersQueryComponent, +} from '../../graphql/types'; import { inputsModel, networkModel, networkSelectors, State, inputsSelectors } from '../../store'; import { withKibana, WithKibanaProps } from '../../lib/kibana'; import { createFilter, getDefaultFetchPolicy } from '../helpers'; import { generateTablePaginationOptions } from '../../components/paginated_table/helpers'; import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated'; -import { usersQuery } from './index.gql_query'; - const ID = 'usersQuery'; export interface UsersArgs { @@ -35,7 +38,7 @@ export interface UsersArgs { } export interface OwnProps extends QueryTemplatePaginatedProps { - children: (args: UsersArgs) => React.ReactNode; + children: (args: UsersArgs) => React.ReactElement; flowTarget: FlowTarget; ip: string; type: networkModel.NetworkType; @@ -81,8 +84,7 @@ class UsersComponentQuery extends QueryTemplatePaginated< }, }; return ( - - query={usersQuery} + + ); } } diff --git a/x-pack/legacy/plugins/siem/public/graphql/introspection.json b/x-pack/legacy/plugins/siem/public/graphql/introspection.json deleted file mode 100644 index 9802a5f5bd3bf..0000000000000 --- a/x-pack/legacy/plugins/siem/public/graphql/introspection.json +++ /dev/null @@ -1,12556 +0,0 @@ -{ - "__schema": { - "queryType": { "name": "Query" }, - "mutationType": { "name": "Mutation" }, - "subscriptionType": null, - "types": [ - { - "kind": "OBJECT", - "name": "Query", - "description": "", - "fields": [ - { - "name": "getNote", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NoteResult", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "getNotesByTimelineId", - "description": "", - "args": [ - { - "name": "timelineId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NoteResult", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "getNotesByEventId", - "description": "", - "args": [ - { - "name": "eventId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NoteResult", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "getAllNotes", - "description": "", - "args": [ - { - "name": "pageInfo", - "description": "", - "type": { "kind": "INPUT_OBJECT", "name": "PageInfoNote", "ofType": null }, - "defaultValue": null - }, - { - "name": "search", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "sort", - "description": "", - "type": { "kind": "INPUT_OBJECT", "name": "SortNote", "ofType": null }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "ResponseNotes", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "getAllPinnedEventsByTimelineId", - "description": "", - "args": [ - { - "name": "timelineId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PinnedEvent", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "source", - "description": "Get a security data source by id", - "args": [ - { - "name": "id", - "description": "The id of the source", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "Source", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "allSources", - "description": "Get a list of all security data sources", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "Source", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "getOneTimeline", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "TimelineResult", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "getAllTimeline", - "description": "", - "args": [ - { - "name": "pageInfo", - "description": "", - "type": { "kind": "INPUT_OBJECT", "name": "PageInfoTimeline", "ofType": null }, - "defaultValue": null - }, - { - "name": "search", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "sort", - "description": "", - "type": { "kind": "INPUT_OBJECT", "name": "SortTimeline", "ofType": null }, - "defaultValue": null - }, - { - "name": "onlyUserFavorite", - "description": "", - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "ResponseTimelines", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "ID", - "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NoteResult", - "description": "", - "fields": [ - { - "name": "eventId", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "note", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timelineId", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "noteId", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "created", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdBy", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timelineVersion", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updated", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedBy", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "version", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "String", - "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Float", - "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PageInfoNote", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "pageIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "pageSize", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "SortNote", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "sortField", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "SortFieldNote", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "sortOrder", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "Direction", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "SortFieldNote", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "updatedBy", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { "name": "updated", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "Direction", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { "name": "asc", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "desc", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ResponseNotes", - "description": "", - "fields": [ - { - "name": "notes", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NoteResult", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PinnedEvent", - "description": "", - "fields": [ - { - "name": "code", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pinnedEventId", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "eventId", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timelineId", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timelineVersion", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "created", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdBy", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updated", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedBy", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "version", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Source", - "description": "", - "fields": [ - { - "name": "id", - "description": "The id of the source", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "configuration", - "description": "The raw configuration of the source", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "SourceConfiguration", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "status", - "description": "The status of the source", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "SourceStatus", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Authentications", - "description": "Gets Authentication success and failures based on a timerange", - "args": [ - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "pagination", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PaginationInputPaginated", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "AuthenticationsData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Timeline", - "description": "", - "args": [ - { - "name": "pagination", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "PaginationInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "sortField", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "SortField", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "fieldRequested", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "TimelineData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "TimelineDetails", - "description": "", - "args": [ - { - "name": "eventId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "indexName", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "TimelineDetailsData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "LastEventTime", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "indexKey", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "LastEventIndexKey", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "details", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "LastTimeDetails", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "LastEventTimeData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Hosts", - "description": "Gets Hosts based on timerange and specified criteria, or all events in the timerange if no criteria is specified", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "pagination", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PaginationInputPaginated", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "sort", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "HostsSortField", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "HostsData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "HostOverview", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "hostName", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "HostItem", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "HostFirstLastSeen", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "hostName", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "FirstLastSeenHost", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "IpOverview", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "ip", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "IpOverviewData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Users", - "description": "", - "args": [ - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "ip", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "pagination", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PaginationInputPaginated", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "sort", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "UsersSortField", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "flowTarget", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "FlowTarget", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "UsersData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "KpiNetwork", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "KpiNetworkData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "KpiHosts", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiHostsData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "KpiHostDetails", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiHostDetailsData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MatrixHistogram", - "description": "", - "args": [ - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "stackByField", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "histogramType", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "HistogramType", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "MatrixHistogramOverTimeData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "NetworkTopCountries", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "ip", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "flowTarget", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "FlowTargetSourceDest", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "pagination", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PaginationInputPaginated", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "sort", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "NetworkTopTablesSortField", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkTopCountriesData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "NetworkTopNFlow", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "ip", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "flowTarget", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "FlowTargetSourceDest", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "pagination", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PaginationInputPaginated", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "sort", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "NetworkTopTablesSortField", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkTopNFlowData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "NetworkDns", - "description": "", - "args": [ - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "isPtrIncluded", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "pagination", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PaginationInputPaginated", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "sort", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "NetworkDnsSortField", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "stackByField", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkDnsData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "NetworkDnsHistogram", - "description": "", - "args": [ - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "stackByField", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkDsOverTimeData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "NetworkHttp", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "ip", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "pagination", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PaginationInputPaginated", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "sort", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "NetworkHttpSortField", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkHttpData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OverviewNetwork", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "OverviewNetworkData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OverviewHost", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "OverviewHostData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Tls", - "description": "", - "args": [ - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "ip", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "pagination", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PaginationInputPaginated", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "sort", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TlsSortField", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "flowTarget", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "FlowTargetSourceDest", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "TlsData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UncommonProcesses", - "description": "Gets UncommonProcesses based on a timerange, or all UncommonProcesses if no criteria is specified", - "args": [ - { - "name": "timerange", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "pagination", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PaginationInputPaginated", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filterQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "UncommonProcessesData", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "whoAmI", - "description": "Just a simple example to get the app name", - "args": [], - "type": { "kind": "OBJECT", "name": "SayMyName", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SourceConfiguration", - "description": "A set of configuration options for a security data source", - "fields": [ - { - "name": "fields", - "description": "The field mapping to use for this source", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "SourceFields", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SourceFields", - "description": "A mapping of semantic fields to their document counterparts", - "fields": [ - { - "name": "container", - "description": "The field to identify a container by", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "host", - "description": "The fields to identify a host by", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": "The fields that may contain the log event message. The first field found win.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pod", - "description": "The field to identify a pod by", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "tiebreaker", - "description": "The field to use as a tiebreaker for log events that have identical timestamps", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timestamp", - "description": "The field to use as a timestamp for metrics and logs", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SourceStatus", - "description": "The status of an infrastructure data source", - "fields": [ - { - "name": "indicesExist", - "description": "Whether the configured alias or wildcard pattern resolve to any auditbeat indices", - "args": [ - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "indexFields", - "description": "The list of fields defined in the index mappings", - "args": [ - { - "name": "defaultIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "IndexField", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Boolean", - "description": "The `Boolean` scalar type represents `true` or `false`.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "IndexField", - "description": "A descriptor of a field in an index", - "fields": [ - { - "name": "category", - "description": "Where the field belong", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "example", - "description": "Example of field's value", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "indexes", - "description": "whether the field's belong to an alias index", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of the field", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "The type of the field's values as recognized by Kibana", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "searchable", - "description": "Whether the field's values can be efficiently searched for", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "aggregatable", - "description": "Whether the field's values can be aggregated", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": "Description of the field", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "format", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "TimerangeInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "interval", - "description": "The interval string to use for last bucket. The format is '{value}{unit}'. For example '5m' would return the metrics for the last 5 minutes of the timespan.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "to", - "description": "The end of the timerange", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "from", - "description": "The beginning of the timerange", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PaginationInputPaginated", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "activePage", - "description": "The activePage parameter defines the page of results you want to fetch", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "cursorStart", - "description": "The cursorStart parameter defines the start of the results to be displayed", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "fakePossibleCount", - "description": "The fakePossibleCount parameter determines the total count in order to show 5 additional pages", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "querySize", - "description": "The querySize parameter is the number of items to be returned", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AuthenticationsData", - "description": "", - "fields": [ - { - "name": "edges", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "AuthenticationsEdges", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfoPaginated", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AuthenticationsEdges", - "description": "", - "fields": [ - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "AuthenticationItem", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CursorType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AuthenticationItem", - "description": "", - "fields": [ - { - "name": "_id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "failures", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "successes", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "user", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "UserEcsFields", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastSuccess", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "LastSourceHost", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastFailure", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "LastSourceHost", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "UserEcsFields", - "description": "", - "fields": [ - { - "name": "domain", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "full_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "email", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "group", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "ToStringArray", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "LastSourceHost", - "description": "", - "fields": [ - { - "name": "timestamp", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Date", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "source", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "SourceEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "host", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "HostEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Date", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SourceEcsFields", - "description": "", - "fields": [ - { - "name": "bytes", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ip", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "port", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "domain", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "geo", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "GeoEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "packets", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "ToNumberArray", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "GeoEcsFields", - "description": "", - "fields": [ - { - "name": "city_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "continent_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "country_iso_code", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "country_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "location", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Location", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "region_iso_code", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "region_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Location", - "description": "", - "fields": [ - { - "name": "lon", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lat", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "HostEcsFields", - "description": "", - "fields": [ - { - "name": "architecture", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ip", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mac", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "os", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "OsEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "OsEcsFields", - "description": "", - "fields": [ - { - "name": "platform", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "full", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "family", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "version", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "kernel", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "CursorType", - "description": "", - "fields": [ - { - "name": "value", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "tiebreaker", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PageInfoPaginated", - "description": "", - "fields": [ - { - "name": "activePage", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fakeTotalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "showMorePagesIndicator", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Inspect", - "description": "", - "fields": [ - { - "name": "dsl", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "response", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PaginationInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "limit", - "description": "The limit parameter allows you to configure the maximum amount of items to be returned", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "cursor", - "description": "The cursor parameter defines the next result you want to fetch", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "tiebreaker", - "description": "The tiebreaker parameter allow to be more precise to fetch the next item", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "SortField", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "sortFieldId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "direction", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "Direction", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TimelineData", - "description": "", - "fields": [ - { - "name": "edges", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "TimelineEdges", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TimelineEdges", - "description": "", - "fields": [ - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "TimelineItem", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CursorType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TimelineItem", - "description": "", - "fields": [ - { - "name": "_id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_index", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "data", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "TimelineNonEcsData", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ecs", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "ECS", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TimelineNonEcsData", - "description": "", - "fields": [ - { - "name": "field", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "value", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ECS", - "description": "", - "fields": [ - { - "name": "_id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_index", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "auditd", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "AuditdEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "destination", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "DestinationEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dns", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "DnsEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "endgame", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "EndgameEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "event", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "EventEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "geo", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "GeoEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "host", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "HostEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "network", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "NetworkEcsField", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "rule", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "RuleEcsField", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "signal", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "SignalField", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "source", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "SourceEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "suricata", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "SuricataEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "tls", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "TlsEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "zeek", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "ZeekEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "http", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "HttpEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "url", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "UrlEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timestamp", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Date", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "user", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "UserEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "winlog", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "WinlogEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "process", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "ProcessEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "file", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "FileFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "system", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "SystemEcsField", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AuditdEcsFields", - "description": "", - "fields": [ - { - "name": "result", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "session", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "data", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "AuditdData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "summary", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Summary", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "sequence", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AuditdData", - "description": "", - "fields": [ - { - "name": "acct", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "terminal", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "op", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Summary", - "description": "", - "fields": [ - { - "name": "actor", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "PrimarySecondary", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "object", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "PrimarySecondary", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "how", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message_type", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "sequence", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PrimarySecondary", - "description": "", - "fields": [ - { - "name": "primary", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "secondary", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "DestinationEcsFields", - "description": "", - "fields": [ - { - "name": "bytes", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ip", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "port", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "domain", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "geo", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "GeoEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "packets", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "DnsEcsFields", - "description": "", - "fields": [ - { - "name": "question", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "DnsQuestionData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "resolved_ip", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "response_code", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "DnsQuestionData", - "description": "", - "fields": [ - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "EndgameEcsFields", - "description": "", - "fields": [ - { - "name": "exit_code", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "file_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "file_path", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "logon_type", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "parent_process_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pid", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "process_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subject_domain_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subject_logon_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subject_user_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "target_domain_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "target_logon_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "target_user_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "EventEcsFields", - "description": "", - "fields": [ - { - "name": "action", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "category", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "code", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "created", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToDateArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dataset", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "duration", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "end", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToDateArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hash", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "kind", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "module", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "original", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "outcome", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "risk_score", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "risk_score_norm", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "severity", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "start", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToDateArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timezone", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "ToDateArray", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkEcsField", - "description": "", - "fields": [ - { - "name": "bytes", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "community_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "direction", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "packets", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "protocol", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "transport", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RuleEcsField", - "description": "", - "fields": [ - { - "name": "reference", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SignalField", - "description": "", - "fields": [ - { - "name": "rule", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "RuleField", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "original_time", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RuleField", - "description": "", - "fields": [ - { - "name": "id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "rule_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "false_positives", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "saved_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timeline_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timeline_title", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "max_signals", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "risk_score", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "output_index", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "from", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "immutable", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "index", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "interval", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "language", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "query", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "references", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "severity", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "tags", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "threat", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToAny", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "size", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "to", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enabled", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "filters", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToAny", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "created_at", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updated_at", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "created_by", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updated_by", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "version", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "ToBooleanArray", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "ToAny", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SuricataEcsFields", - "description": "", - "fields": [ - { - "name": "eve", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "SuricataEveData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SuricataEveData", - "description": "", - "fields": [ - { - "name": "alert", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "SuricataAlertData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "flow_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "proto", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SuricataAlertData", - "description": "", - "fields": [ - { - "name": "signature", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "signature_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TlsEcsFields", - "description": "", - "fields": [ - { - "name": "client_certificate", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "TlsClientCertificateData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fingerprints", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "TlsFingerprintsData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "server_certificate", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "TlsServerCertificateData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TlsClientCertificateData", - "description": "", - "fields": [ - { - "name": "fingerprint", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "FingerprintData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "FingerprintData", - "description": "", - "fields": [ - { - "name": "sha1", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TlsFingerprintsData", - "description": "", - "fields": [ - { - "name": "ja3", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "TlsJa3Data", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TlsJa3Data", - "description": "", - "fields": [ - { - "name": "hash", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TlsServerCertificateData", - "description": "", - "fields": [ - { - "name": "fingerprint", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "FingerprintData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ZeekEcsFields", - "description": "", - "fields": [ - { - "name": "session_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "connection", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "ZeekConnectionData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "notice", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "ZeekNoticeData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dns", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "ZeekDnsData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "http", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "ZeekHttpData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "files", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "ZeekFileData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ssl", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "ZeekSslData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ZeekConnectionData", - "description": "", - "fields": [ - { - "name": "local_resp", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "local_orig", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "missed_bytes", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "state", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "history", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ZeekNoticeData", - "description": "", - "fields": [ - { - "name": "suppress_for", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "msg", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "note", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "sub", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dst", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dropped", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "peer_descr", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ZeekDnsData", - "description": "", - "fields": [ - { - "name": "AA", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "qclass_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "RD", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "qtype_name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "rejected", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "qtype", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "query", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "trans_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "qclass", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "RA", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "TC", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ZeekHttpData", - "description": "", - "fields": [ - { - "name": "resp_mime_types", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "trans_depth", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "status_msg", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "resp_fuids", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "tags", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ZeekFileData", - "description": "", - "fields": [ - { - "name": "session_ids", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timedout", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "local_orig", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "tx_host", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "source", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "is_orig", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "overflow_bytes", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "sha1", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "duration", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "depth", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "analyzers", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mime_type", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "rx_host", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "total_bytes", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fuid", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "seen_bytes", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "missing_bytes", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "md5", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ZeekSslData", - "description": "", - "fields": [ - { - "name": "cipher", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "established", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "resumed", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToBooleanArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "version", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "HttpEcsFields", - "description": "", - "fields": [ - { - "name": "version", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "request", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "HttpRequestData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "response", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "HttpResponseData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "HttpRequestData", - "description": "", - "fields": [ - { - "name": "method", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "body", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "HttpBodyData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "referrer", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "bytes", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "HttpBodyData", - "description": "", - "fields": [ - { - "name": "content", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "bytes", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "HttpResponseData", - "description": "", - "fields": [ - { - "name": "status_code", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "body", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "HttpBodyData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "bytes", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "UrlEcsFields", - "description": "", - "fields": [ - { - "name": "domain", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "original", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "username", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "password", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "WinlogEcsFields", - "description": "", - "fields": [ - { - "name": "event_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ProcessEcsFields", - "description": "", - "fields": [ - { - "name": "hash", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "ProcessHashData", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pid", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ppid", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "executable", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "title", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "thread", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Thread", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "working_directory", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ProcessHashData", - "description": "", - "fields": [ - { - "name": "md5", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "sha1", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "sha256", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Thread", - "description": "", - "fields": [ - { - "name": "id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "start", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "FileFields", - "description": "", - "fields": [ - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "path", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "target_path", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "extension", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "device", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inode", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uid", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "owner", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gid", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "group", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mode", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "size", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mtime", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToDateArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ctime", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToDateArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SystemEcsField", - "description": "", - "fields": [ - { - "name": "audit", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "AuditEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "auth", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "AuthEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AuditEcsFields", - "description": "", - "fields": [ - { - "name": "package", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "PackageEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PackageEcsFields", - "description": "", - "fields": [ - { - "name": "arch", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "entity_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "size", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToNumberArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "summary", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "version", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AuthEcsFields", - "description": "", - "fields": [ - { - "name": "ssh", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "SshEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SshEcsFields", - "description": "", - "fields": [ - { - "name": "method", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "signature", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PageInfo", - "description": "", - "fields": [ - { - "name": "endCursor", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "CursorType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hasNextPage", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TimelineDetailsData", - "description": "", - "fields": [ - { - "name": "data", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "DetailItem", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "DetailItem", - "description": "", - "fields": [ - { - "name": "field", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "values", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "originalValue", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "EsValue", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "EsValue", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "LastEventIndexKey", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "hostDetails", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { "name": "hosts", "description": "", "isDeprecated": false, "deprecationReason": null }, - { - "name": "ipDetails", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { "name": "network", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "LastTimeDetails", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "hostName", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "ip", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "LastEventTimeData", - "description": "", - "fields": [ - { - "name": "lastSeen", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Date", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "HostsSortField", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "field", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "HostsFields", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "direction", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "Direction", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "HostsFields", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "hostName", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastSeen", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "HostsData", - "description": "", - "fields": [ - { - "name": "edges", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "HostsEdges", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfoPaginated", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "HostsEdges", - "description": "", - "fields": [ - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "HostItem", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CursorType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "HostItem", - "description": "", - "fields": [ - { - "name": "_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastSeen", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Date", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "host", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "HostEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cloud", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "CloudFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "CloudFields", - "description": "", - "fields": [ - { - "name": "instance", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "CloudInstance", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "machine", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "CloudMachine", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "provider", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "region", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "CloudInstance", - "description": "", - "fields": [ - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "CloudMachine", - "description": "", - "fields": [ - { - "name": "type", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "FirstLastSeenHost", - "description": "", - "fields": [ - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "firstSeen", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Date", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastSeen", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Date", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "IpOverviewData", - "description": "", - "fields": [ - { - "name": "client", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Overview", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "destination", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Overview", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "host", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "HostEcsFields", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "server", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Overview", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "source", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Overview", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Overview", - "description": "", - "fields": [ - { - "name": "firstSeen", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Date", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastSeen", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Date", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "autonomousSystem", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "AutonomousSystem", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "geo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "GeoEcsFields", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AutonomousSystem", - "description": "", - "fields": [ - { - "name": "number", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "organization", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "AutonomousSystemOrganization", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AutonomousSystemOrganization", - "description": "", - "fields": [ - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UsersSortField", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "field", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "UsersFields", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "direction", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "Direction", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "UsersFields", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { "name": "name", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "count", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "FlowTarget", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { "name": "client", "description": "", "isDeprecated": false, "deprecationReason": null }, - { - "name": "destination", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { "name": "server", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "source", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "UsersData", - "description": "", - "fields": [ - { - "name": "edges", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "UsersEdges", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfoPaginated", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "UsersEdges", - "description": "", - "fields": [ - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "UsersNode", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CursorType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "UsersNode", - "description": "", - "fields": [ - { - "name": "_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timestamp", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Date", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "user", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "UsersItem", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "UsersItem", - "description": "", - "fields": [ - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "groupId", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "groupName", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "ToStringArray", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "count", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "KpiNetworkData", - "description": "", - "fields": [ - { - "name": "networkEvents", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueFlowId", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueSourcePrivateIps", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueSourcePrivateIpsHistogram", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiNetworkHistogramData", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueDestinationPrivateIps", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueDestinationPrivateIpsHistogram", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiNetworkHistogramData", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dnsQueries", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "tlsHandshakes", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "KpiNetworkHistogramData", - "description": "", - "fields": [ - { - "name": "x", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "y", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "KpiHostsData", - "description": "", - "fields": [ - { - "name": "hosts", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hostsHistogram", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiHostHistogramData", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "authSuccess", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "authSuccessHistogram", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiHostHistogramData", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "authFailure", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "authFailureHistogram", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiHostHistogramData", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueSourceIps", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueSourceIpsHistogram", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiHostHistogramData", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueDestinationIps", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueDestinationIpsHistogram", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiHostHistogramData", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "KpiHostHistogramData", - "description": "", - "fields": [ - { - "name": "x", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "y", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "KpiHostDetailsData", - "description": "", - "fields": [ - { - "name": "authSuccess", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "authSuccessHistogram", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiHostHistogramData", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "authFailure", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "authFailureHistogram", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiHostHistogramData", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueSourceIps", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueSourceIpsHistogram", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiHostHistogramData", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueDestinationIps", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueDestinationIpsHistogram", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "KpiHostHistogramData", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "HistogramType", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "authentications", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "anomalies", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { "name": "events", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "alerts", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "dns", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "MatrixHistogramOverTimeData", - "description": "", - "fields": [ - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "matrixHistogramData", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MatrixOverTimeHistogramData", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "MatrixOverTimeHistogramData", - "description": "", - "fields": [ - { - "name": "x", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "y", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "g", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "FlowTargetSourceDest", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "destination", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { "name": "source", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "NetworkTopTablesSortField", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "field", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "NetworkTopTablesFields", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "direction", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "Direction", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "NetworkTopTablesFields", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "bytes_in", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "bytes_out", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { "name": "flows", "description": "", "isDeprecated": false, "deprecationReason": null }, - { - "name": "destination_ips", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "source_ips", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkTopCountriesData", - "description": "", - "fields": [ - { - "name": "edges", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkTopCountriesEdges", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfoPaginated", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkTopCountriesEdges", - "description": "", - "fields": [ - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkTopCountriesItem", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CursorType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkTopCountriesItem", - "description": "", - "fields": [ - { - "name": "_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "source", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "TopCountriesItemSource", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "destination", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "TopCountriesItemDestination", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "network", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "TopNetworkTablesEcsField", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TopCountriesItemSource", - "description": "", - "fields": [ - { - "name": "country", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "destination_ips", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "flows", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "location", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "GeoItem", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "source_ips", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "GeoItem", - "description": "", - "fields": [ - { - "name": "geo", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "GeoEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "flowTarget", - "description": "", - "args": [], - "type": { "kind": "ENUM", "name": "FlowTargetSourceDest", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TopCountriesItemDestination", - "description": "", - "fields": [ - { - "name": "country", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "destination_ips", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "flows", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "location", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "GeoItem", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "source_ips", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TopNetworkTablesEcsField", - "description": "", - "fields": [ - { - "name": "bytes_in", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "bytes_out", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkTopNFlowData", - "description": "", - "fields": [ - { - "name": "edges", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkTopNFlowEdges", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfoPaginated", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkTopNFlowEdges", - "description": "", - "fields": [ - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkTopNFlowItem", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CursorType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkTopNFlowItem", - "description": "", - "fields": [ - { - "name": "_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "source", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "TopNFlowItemSource", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "destination", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "TopNFlowItemDestination", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "network", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "TopNetworkTablesEcsField", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TopNFlowItemSource", - "description": "", - "fields": [ - { - "name": "autonomous_system", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "AutonomousSystemItem", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "domain", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ip", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "location", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "GeoItem", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "flows", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "destination_ips", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AutonomousSystemItem", - "description": "", - "fields": [ - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "number", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TopNFlowItemDestination", - "description": "", - "fields": [ - { - "name": "autonomous_system", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "AutonomousSystemItem", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "domain", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ip", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "location", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "GeoItem", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "flows", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "source_ips", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "NetworkDnsSortField", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "field", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "NetworkDnsFields", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "direction", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "Direction", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "NetworkDnsFields", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "dnsName", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "queryCount", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueDomains", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dnsBytesIn", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dnsBytesOut", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkDnsData", - "description": "", - "fields": [ - { - "name": "edges", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkDnsEdges", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfoPaginated", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "histogram", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MatrixOverOrdinalHistogramData", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkDnsEdges", - "description": "", - "fields": [ - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkDnsItem", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CursorType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkDnsItem", - "description": "", - "fields": [ - { - "name": "_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dnsBytesIn", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dnsBytesOut", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dnsName", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "queryCount", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "uniqueDomains", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "MatrixOverOrdinalHistogramData", - "description": "", - "fields": [ - { - "name": "x", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "y", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "g", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkDsOverTimeData", - "description": "", - "fields": [ - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "matrixHistogramData", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "MatrixOverTimeHistogramData", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "NetworkHttpSortField", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "direction", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "Direction", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkHttpData", - "description": "", - "fields": [ - { - "name": "edges", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkHttpEdges", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfoPaginated", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkHttpEdges", - "description": "", - "fields": [ - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NetworkHttpItem", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CursorType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "NetworkHttpItem", - "description": "", - "fields": [ - { - "name": "_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "domains", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastHost", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastSourceIp", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "methods", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "path", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "requestCount", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "statuses", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "OverviewNetworkData", - "description": "", - "fields": [ - { - "name": "auditbeatSocket", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "filebeatCisco", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "filebeatNetflow", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "filebeatPanw", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "filebeatSuricata", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "filebeatZeek", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "packetbeatDNS", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "packetbeatFlow", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "packetbeatTLS", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "OverviewHostData", - "description": "", - "fields": [ - { - "name": "auditbeatAuditd", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "auditbeatFIM", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "auditbeatLogin", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "auditbeatPackage", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "auditbeatProcess", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "auditbeatUser", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "endgameDns", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "endgameFile", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "endgameImageLoad", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "endgameNetwork", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "endgameProcess", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "endgameRegistry", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "endgameSecurity", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "filebeatSystemModule", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "winlogbeatSecurity", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "winlogbeatMWSysmonOperational", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "TlsSortField", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "field", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "TlsFields", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "direction", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "Direction", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "TlsFields", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { "name": "_id", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TlsData", - "description": "", - "fields": [ - { - "name": "edges", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "TlsEdges", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfoPaginated", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TlsEdges", - "description": "", - "fields": [ - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "TlsNode", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CursorType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TlsNode", - "description": "", - "fields": [ - { - "name": "_id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timestamp", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Date", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "alternativeNames", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "notAfter", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "commonNames", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ja3", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "issuerNames", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "UncommonProcessesData", - "description": "", - "fields": [ - { - "name": "edges", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "UncommonProcessesEdges", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfoPaginated", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "UncommonProcessesEdges", - "description": "", - "fields": [ - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "UncommonProcessItem", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CursorType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "UncommonProcessItem", - "description": "", - "fields": [ - { - "name": "_id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "instances", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "process", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "ProcessEcsFields", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hosts", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "HostEcsFields", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "user", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "UserEcsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SayMyName", - "description": "", - "fields": [ - { - "name": "appName", - "description": "The id of the source", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "TimelineResult", - "description": "", - "fields": [ - { - "name": "columns", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "ColumnHeaderResult", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "created", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdBy", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dataProviders", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "DataProviderResult", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dateRange", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "DateRangePickerResult", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "eventIdToNoteIds", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NoteResult", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "eventType", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "favorite", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "FavoriteTimelineResult", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "filters", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "FilterTimelineResult", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "kqlMode", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "kqlQuery", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "SerializedFilterQueryResult", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "notes", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NoteResult", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "noteIds", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pinnedEventIds", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pinnedEventsSaveObject", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PinnedEvent", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "savedQueryId", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "savedObjectId", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "sort", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "SortTimelineResult", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "title", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updated", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedBy", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "version", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ColumnHeaderResult", - "description": "", - "fields": [ - { - "name": "aggregatable", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "category", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "columnHeaderType", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "example", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "indexes", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "placeholder", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "searchable", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "DataProviderResult", - "description": "", - "fields": [ - { - "name": "id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enabled", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "excluded", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "kqlQuery", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "queryMatch", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "QueryMatchResult", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "and", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "DataProviderResult", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "QueryMatchResult", - "description": "", - "fields": [ - { - "name": "field", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "displayField", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "value", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "displayValue", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "operator", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "DateRangePickerResult", - "description": "", - "fields": [ - { - "name": "start", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "end", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "FavoriteTimelineResult", - "description": "", - "fields": [ - { - "name": "fullName", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "userName", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "favoriteDate", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "FilterTimelineResult", - "description": "", - "fields": [ - { - "name": "exists", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "meta", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "FilterMetaTimelineResult", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "match_all", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "missing", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "query", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "range", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "script", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "FilterMetaTimelineResult", - "description": "", - "fields": [ - { - "name": "alias", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "controlledBy", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "disabled", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "field", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "formattedValue", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "index", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "key", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "negate", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "params", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "value", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SerializedFilterQueryResult", - "description": "", - "fields": [ - { - "name": "filterQuery", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "SerializedKueryQueryResult", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SerializedKueryQueryResult", - "description": "", - "fields": [ - { - "name": "kuery", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "KueryFilterQueryResult", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "serializedQuery", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "KueryFilterQueryResult", - "description": "", - "fields": [ - { - "name": "kind", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "expression", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SortTimelineResult", - "description": "", - "fields": [ - { - "name": "columnId", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "sortDirection", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PageInfoTimeline", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "pageIndex", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "pageSize", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "SortTimeline", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "sortField", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "SortFieldTimeline", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "sortOrder", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "Direction", "ofType": null } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "SortFieldTimeline", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { "name": "title", "description": "", "isDeprecated": false, "deprecationReason": null }, - { - "name": "description", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updated", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { "name": "created", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ResponseTimelines", - "description": "", - "fields": [ - { - "name": "timeline", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "OBJECT", "name": "TimelineResult", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Mutation", - "description": "", - "fields": [ - { - "name": "persistNote", - "description": "Persists a note", - "args": [ - { - "name": "noteId", - "description": "", - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - }, - { - "name": "version", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "note", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "NoteInput", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "ResponseNote", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deleteNote", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deleteNoteByTimelineId", - "description": "", - "args": [ - { - "name": "timelineId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "version", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "persistPinnedEventOnTimeline", - "description": "Persists a pinned event in a timeline", - "args": [ - { - "name": "pinnedEventId", - "description": "", - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - }, - { - "name": "eventId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - }, - { - "name": "timelineId", - "description": "", - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "PinnedEvent", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deletePinnedEventOnTimeline", - "description": "Remove a pinned events in a timeline", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deleteAllPinnedEventsOnTimeline", - "description": "Remove all pinned events in a timeline", - "args": [ - { - "name": "timelineId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "persistTimeline", - "description": "Persists a timeline", - "args": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - }, - { - "name": "version", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "timeline", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "TimelineInput", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "ResponseTimeline", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "persistFavorite", - "description": "", - "args": [ - { - "name": "timelineId", - "description": "", - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "ResponseFavoriteTimeline", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deleteTimeline", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "NoteInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "eventId", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "note", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "timelineId", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ResponseNote", - "description": "", - "fields": [ - { - "name": "code", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "note", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "NoteResult", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "TimelineInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "columns", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "ColumnHeaderInput", "ofType": null } - } - }, - "defaultValue": null - }, - { - "name": "dataProviders", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "DataProviderInput", "ofType": null } - } - }, - "defaultValue": null - }, - { - "name": "description", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "eventType", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "filters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "FilterTimelineInput", "ofType": null } - } - }, - "defaultValue": null - }, - { - "name": "kqlMode", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "kqlQuery", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SerializedFilterQueryInput", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "dateRange", - "description": "", - "type": { "kind": "INPUT_OBJECT", "name": "DateRangePickerInput", "ofType": null }, - "defaultValue": null - }, - { - "name": "savedQueryId", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "sort", - "description": "", - "type": { "kind": "INPUT_OBJECT", "name": "SortTimelineInput", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "ColumnHeaderInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "aggregatable", - "description": "", - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "category", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "columnHeaderType", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "description", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "example", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "indexes", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "placeholder", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "searchable", - "description": "", - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "type", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "DataProviderInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "id", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "enabled", - "description": "", - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "excluded", - "description": "", - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "kqlQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "queryMatch", - "description": "", - "type": { "kind": "INPUT_OBJECT", "name": "QueryMatchInput", "ofType": null }, - "defaultValue": null - }, - { - "name": "and", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "INPUT_OBJECT", "name": "DataProviderInput", "ofType": null } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "QueryMatchInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "field", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "displayField", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "value", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "displayValue", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "operator", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "FilterTimelineInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "exists", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "meta", - "description": "", - "type": { "kind": "INPUT_OBJECT", "name": "FilterMetaTimelineInput", "ofType": null }, - "defaultValue": null - }, - { - "name": "match_all", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "missing", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "query", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "range", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "script", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "FilterMetaTimelineInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "alias", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "controlledBy", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "disabled", - "description": "", - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "field", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "formattedValue", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "index", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "key", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "negate", - "description": "", - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "params", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "type", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "value", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "SerializedFilterQueryInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "filterQuery", - "description": "", - "type": { "kind": "INPUT_OBJECT", "name": "SerializedKueryQueryInput", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "SerializedKueryQueryInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "kuery", - "description": "", - "type": { "kind": "INPUT_OBJECT", "name": "KueryFilterQueryInput", "ofType": null }, - "defaultValue": null - }, - { - "name": "serializedQuery", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "KueryFilterQueryInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "kind", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "expression", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "DateRangePickerInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "start", - "description": "", - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "defaultValue": null - }, - { - "name": "end", - "description": "", - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "SortTimelineInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "columnId", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "sortDirection", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ResponseTimeline", - "description": "", - "fields": [ - { - "name": "code", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "timeline", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "TimelineResult", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "ResponseFavoriteTimeline", - "description": "", - "fields": [ - { - "name": "code", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "message", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "savedObjectId", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "version", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "favorite", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "FavoriteTimelineResult", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Schema", - "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", - "fields": [ - { - "name": "types", - "description": "A list of all types supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "queryType", - "description": "The type that query operations will be rooted at.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mutationType", - "description": "If this server supports mutation, the type that mutation operations will be rooted at.", - "args": [], - "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subscriptionType", - "description": "If this server support subscription, the type that subscription operations will be rooted at.", - "args": [], - "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "directives", - "description": "A list of all directives supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Directive", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Type", - "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", - "fields": [ - { - "name": "kind", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "__TypeKind", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fields", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Field", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "interfaces", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "possibleTypes", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enumValues", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__EnumValue", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inputFields", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ofType", - "description": null, - "args": [], - "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__TypeKind", - "description": "An enum describing what kind of type a given `__Type` is.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "SCALAR", - "description": "Indicates this type is a scalar.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Indicates this type is a union. `possibleTypes` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Indicates this type is an enum. `enumValues` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Indicates this type is an input object. `inputFields` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "LIST", - "description": "Indicates this type is a list. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "NON_NULL", - "description": "Indicates this type is a non-null. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Field", - "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__InputValue", - "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "defaultValue", - "description": "A GraphQL-formatted string representing the default value for this input value.", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__EnumValue", - "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Directive", - "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "locations", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "__DirectiveLocation", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "onOperation", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - }, - { - "name": "onFragment", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - }, - { - "name": "onField", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__DirectiveLocation", - "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "QUERY", - "description": "Location adjacent to a query operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MUTATION", - "description": "Location adjacent to a mutation operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SUBSCRIPTION", - "description": "Location adjacent to a subscription operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD", - "description": "Location adjacent to a field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_DEFINITION", - "description": "Location adjacent to a fragment definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_SPREAD", - "description": "Location adjacent to a fragment spread.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INLINE_FRAGMENT", - "description": "Location adjacent to an inline fragment.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCHEMA", - "description": "Location adjacent to a schema definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCALAR", - "description": "Location adjacent to a scalar definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Location adjacent to an object type definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD_DEFINITION", - "description": "Location adjacent to a field definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ARGUMENT_DEFINITION", - "description": "Location adjacent to an argument definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Location adjacent to an interface definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Location adjacent to a union definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Location adjacent to an enum definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM_VALUE", - "description": "Location adjacent to an enum value definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Location adjacent to an input object type definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_FIELD_DEFINITION", - "description": "Location adjacent to an input object field definition.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "EcsEdges", - "description": "", - "fields": [ - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "ECS", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CursorType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "EventsTimelineData", - "description": "", - "fields": [ - { - "name": "edges", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "EcsEdges", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "totalCount", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inspect", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "OsFields", - "description": "", - "fields": [ - { - "name": "platform", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "full", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "family", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "version", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "kernel", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "HostFields", - "description": "", - "fields": [ - { - "name": "architecture", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ip", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mac", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "os", - "description": "", - "args": [], - "type": { "kind": "OBJECT", "name": "OsFields", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "NetworkDirectionEcs", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "inbound", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "outbound", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "internal", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "external", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "incoming", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "outgoing", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "listening", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { "name": "unknown", "description": "", "isDeprecated": false, "deprecationReason": null } - ], - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "NetworkHttpFields", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "domains", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastHost", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastSourceIp", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "methods", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { "name": "path", "description": "", "isDeprecated": false, "deprecationReason": null }, - { - "name": "requestCount", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "statuses", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "FlowDirection", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "uniDirectional", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "biDirectional", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "FavoriteTimelineInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "fullName", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "userName", - "description": "", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "favoriteDate", - "description": "", - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - } - ], - "directives": [ - { - "name": "skip", - "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", - "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], - "args": [ - { - "name": "if", - "description": "Skipped when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "defaultValue": null - } - ] - }, - { - "name": "include", - "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", - "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "defaultValue": null - } - ] - }, - { - "name": "deprecated", - "description": "Marks an element of a GraphQL schema as no longer supported.", - "locations": ["FIELD_DEFINITION", "ENUM_VALUE"], - "args": [ - { - "name": "reason", - "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": "\"No longer supported\"" - } - ] - } - ] - } -} diff --git a/x-pack/legacy/plugins/siem/public/graphql/types.ts b/x-pack/legacy/plugins/siem/public/graphql/types.ts deleted file mode 100644 index 3528ee6e13a38..0000000000000 --- a/x-pack/legacy/plugins/siem/public/graphql/types.ts +++ /dev/null @@ -1,5943 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -/* - * 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 Maybe = T | null; - -export interface PageInfoNote { - pageIndex: number; - - pageSize: number; -} - -export interface SortNote { - sortField: SortFieldNote; - - sortOrder: Direction; -} - -export interface TimerangeInput { - /** The interval string to use for last bucket. The format is '{value}{unit}'. For example '5m' would return the metrics for the last 5 minutes of the timespan. */ - interval: string; - /** The end of the timerange */ - to: number; - /** The beginning of the timerange */ - from: number; -} - -export interface PaginationInputPaginated { - /** The activePage parameter defines the page of results you want to fetch */ - activePage: number; - /** The cursorStart parameter defines the start of the results to be displayed */ - cursorStart: number; - /** The fakePossibleCount parameter determines the total count in order to show 5 additional pages */ - fakePossibleCount: number; - /** The querySize parameter is the number of items to be returned */ - querySize: number; -} - -export interface PaginationInput { - /** The limit parameter allows you to configure the maximum amount of items to be returned */ - limit: number; - /** The cursor parameter defines the next result you want to fetch */ - cursor?: Maybe; - /** The tiebreaker parameter allow to be more precise to fetch the next item */ - tiebreaker?: Maybe; -} - -export interface SortField { - sortFieldId: string; - - direction: Direction; -} - -export interface LastTimeDetails { - hostName?: Maybe; - - ip?: Maybe; -} - -export interface HostsSortField { - field: HostsFields; - - direction: Direction; -} - -export interface UsersSortField { - field: UsersFields; - - direction: Direction; -} - -export interface NetworkTopTablesSortField { - field: NetworkTopTablesFields; - - direction: Direction; -} - -export interface NetworkDnsSortField { - field: NetworkDnsFields; - - direction: Direction; -} - -export interface NetworkHttpSortField { - direction: Direction; -} - -export interface TlsSortField { - field: TlsFields; - - direction: Direction; -} - -export interface PageInfoTimeline { - pageIndex: number; - - pageSize: number; -} - -export interface SortTimeline { - sortField: SortFieldTimeline; - - sortOrder: Direction; -} - -export interface NoteInput { - eventId?: Maybe; - - note?: Maybe; - - timelineId?: Maybe; -} - -export interface TimelineInput { - columns?: Maybe; - - dataProviders?: Maybe; - - description?: Maybe; - - eventType?: Maybe; - - filters?: Maybe; - - kqlMode?: Maybe; - - kqlQuery?: Maybe; - - title?: Maybe; - - dateRange?: Maybe; - - savedQueryId?: Maybe; - - sort?: Maybe; -} - -export interface ColumnHeaderInput { - aggregatable?: Maybe; - - category?: Maybe; - - columnHeaderType?: Maybe; - - description?: Maybe; - - example?: Maybe; - - indexes?: Maybe; - - id?: Maybe; - - name?: Maybe; - - placeholder?: Maybe; - - searchable?: Maybe; - - type?: Maybe; -} - -export interface DataProviderInput { - id?: Maybe; - - name?: Maybe; - - enabled?: Maybe; - - excluded?: Maybe; - - kqlQuery?: Maybe; - - queryMatch?: Maybe; - - and?: Maybe; -} - -export interface QueryMatchInput { - field?: Maybe; - - displayField?: Maybe; - - value?: Maybe; - - displayValue?: Maybe; - - operator?: Maybe; -} - -export interface FilterTimelineInput { - exists?: Maybe; - - meta?: Maybe; - - match_all?: Maybe; - - missing?: Maybe; - - query?: Maybe; - - range?: Maybe; - - script?: Maybe; -} - -export interface FilterMetaTimelineInput { - alias?: Maybe; - - controlledBy?: Maybe; - - disabled?: Maybe; - - field?: Maybe; - - formattedValue?: Maybe; - - index?: Maybe; - - key?: Maybe; - - negate?: Maybe; - - params?: Maybe; - - type?: Maybe; - - value?: Maybe; -} - -export interface SerializedFilterQueryInput { - filterQuery?: Maybe; -} - -export interface SerializedKueryQueryInput { - kuery?: Maybe; - - serializedQuery?: Maybe; -} - -export interface KueryFilterQueryInput { - kind?: Maybe; - - expression?: Maybe; -} - -export interface DateRangePickerInput { - start?: Maybe; - - end?: Maybe; -} - -export interface SortTimelineInput { - columnId?: Maybe; - - sortDirection?: Maybe; -} - -export interface FavoriteTimelineInput { - fullName?: Maybe; - - userName?: Maybe; - - favoriteDate?: Maybe; -} - -export enum SortFieldNote { - updatedBy = 'updatedBy', - updated = 'updated', -} - -export enum Direction { - asc = 'asc', - desc = 'desc', -} - -export enum LastEventIndexKey { - hostDetails = 'hostDetails', - hosts = 'hosts', - ipDetails = 'ipDetails', - network = 'network', -} - -export enum HostsFields { - hostName = 'hostName', - lastSeen = 'lastSeen', -} - -export enum UsersFields { - name = 'name', - count = 'count', -} - -export enum FlowTarget { - client = 'client', - destination = 'destination', - server = 'server', - source = 'source', -} - -export enum HistogramType { - authentications = 'authentications', - anomalies = 'anomalies', - events = 'events', - alerts = 'alerts', - dns = 'dns', -} - -export enum FlowTargetSourceDest { - destination = 'destination', - source = 'source', -} - -export enum NetworkTopTablesFields { - bytes_in = 'bytes_in', - bytes_out = 'bytes_out', - flows = 'flows', - destination_ips = 'destination_ips', - source_ips = 'source_ips', -} - -export enum NetworkDnsFields { - dnsName = 'dnsName', - queryCount = 'queryCount', - uniqueDomains = 'uniqueDomains', - dnsBytesIn = 'dnsBytesIn', - dnsBytesOut = 'dnsBytesOut', -} - -export enum TlsFields { - _id = '_id', -} - -export enum SortFieldTimeline { - title = 'title', - description = 'description', - updated = 'updated', - created = 'created', -} - -export enum NetworkDirectionEcs { - inbound = 'inbound', - outbound = 'outbound', - internal = 'internal', - external = 'external', - incoming = 'incoming', - outgoing = 'outgoing', - listening = 'listening', - unknown = 'unknown', -} - -export enum NetworkHttpFields { - domains = 'domains', - lastHost = 'lastHost', - lastSourceIp = 'lastSourceIp', - methods = 'methods', - path = 'path', - requestCount = 'requestCount', - statuses = 'statuses', -} - -export enum FlowDirection { - uniDirectional = 'uniDirectional', - biDirectional = 'biDirectional', -} - -export type ToStringArray = string[]; - -export type Date = string; - -export type ToNumberArray = number[]; - -export type ToDateArray = string[]; - -export type ToBooleanArray = boolean[]; - -export type ToAny = any; - -export type EsValue = any; - -// ==================================================== -// Scalars -// ==================================================== - -// ==================================================== -// Types -// ==================================================== - -export interface Query { - getNote: NoteResult; - - getNotesByTimelineId: NoteResult[]; - - getNotesByEventId: NoteResult[]; - - getAllNotes: ResponseNotes; - - getAllPinnedEventsByTimelineId: PinnedEvent[]; - /** Get a security data source by id */ - source: Source; - /** Get a list of all security data sources */ - allSources: Source[]; - - getOneTimeline: TimelineResult; - - getAllTimeline: ResponseTimelines; -} - -export interface NoteResult { - eventId?: Maybe; - - note?: Maybe; - - timelineId?: Maybe; - - noteId: string; - - created?: Maybe; - - createdBy?: Maybe; - - timelineVersion?: Maybe; - - updated?: Maybe; - - updatedBy?: Maybe; - - version?: Maybe; -} - -export interface ResponseNotes { - notes: NoteResult[]; - - totalCount?: Maybe; -} - -export interface PinnedEvent { - code?: Maybe; - - message?: Maybe; - - pinnedEventId: string; - - eventId?: Maybe; - - timelineId?: Maybe; - - timelineVersion?: Maybe; - - created?: Maybe; - - createdBy?: Maybe; - - updated?: Maybe; - - updatedBy?: Maybe; - - version?: Maybe; -} - -export interface Source { - /** The id of the source */ - id: string; - /** The raw configuration of the source */ - configuration: SourceConfiguration; - /** The status of the source */ - status: SourceStatus; - /** Gets Authentication success and failures based on a timerange */ - Authentications: AuthenticationsData; - - Timeline: TimelineData; - - TimelineDetails: TimelineDetailsData; - - LastEventTime: LastEventTimeData; - /** Gets Hosts based on timerange and specified criteria, or all events in the timerange if no criteria is specified */ - Hosts: HostsData; - - HostOverview: HostItem; - - HostFirstLastSeen: FirstLastSeenHost; - - IpOverview?: Maybe; - - Users: UsersData; - - KpiNetwork?: Maybe; - - KpiHosts: KpiHostsData; - - KpiHostDetails: KpiHostDetailsData; - - MatrixHistogram: MatrixHistogramOverTimeData; - - NetworkTopCountries: NetworkTopCountriesData; - - NetworkTopNFlow: NetworkTopNFlowData; - - NetworkDns: NetworkDnsData; - - NetworkDnsHistogram: NetworkDsOverTimeData; - - NetworkHttp: NetworkHttpData; - - OverviewNetwork?: Maybe; - - OverviewHost?: Maybe; - - Tls: TlsData; - /** Gets UncommonProcesses based on a timerange, or all UncommonProcesses if no criteria is specified */ - UncommonProcesses: UncommonProcessesData; - /** Just a simple example to get the app name */ - whoAmI?: Maybe; -} - -/** A set of configuration options for a security data source */ -export interface SourceConfiguration { - /** The field mapping to use for this source */ - fields: SourceFields; -} - -/** A mapping of semantic fields to their document counterparts */ -export interface SourceFields { - /** The field to identify a container by */ - container: string; - /** The fields to identify a host by */ - host: string; - /** The fields that may contain the log event message. The first field found win. */ - message: string[]; - /** The field to identify a pod by */ - pod: string; - /** The field to use as a tiebreaker for log events that have identical timestamps */ - tiebreaker: string; - /** The field to use as a timestamp for metrics and logs */ - timestamp: string; -} - -/** The status of an infrastructure data source */ -export interface SourceStatus { - /** Whether the configured alias or wildcard pattern resolve to any auditbeat indices */ - indicesExist: boolean; - /** The list of fields defined in the index mappings */ - indexFields: IndexField[]; -} - -/** A descriptor of a field in an index */ -export interface IndexField { - /** Where the field belong */ - category: string; - /** Example of field's value */ - example?: Maybe; - /** whether the field's belong to an alias index */ - indexes: (Maybe)[]; - /** The name of the field */ - name: string; - /** The type of the field's values as recognized by Kibana */ - type: string; - /** Whether the field's values can be efficiently searched for */ - searchable: boolean; - /** Whether the field's values can be aggregated */ - aggregatable: boolean; - /** Description of the field */ - description?: Maybe; - - format?: Maybe; -} - -export interface AuthenticationsData { - edges: AuthenticationsEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface AuthenticationsEdges { - node: AuthenticationItem; - - cursor: CursorType; -} - -export interface AuthenticationItem { - _id: string; - - failures: number; - - successes: number; - - user: UserEcsFields; - - lastSuccess?: Maybe; - - lastFailure?: Maybe; -} - -export interface UserEcsFields { - domain?: Maybe; - - id?: Maybe; - - name?: Maybe; - - full_name?: Maybe; - - email?: Maybe; - - hash?: Maybe; - - group?: Maybe; -} - -export interface LastSourceHost { - timestamp?: Maybe; - - source?: Maybe; - - host?: Maybe; -} - -export interface SourceEcsFields { - bytes?: Maybe; - - ip?: Maybe; - - port?: Maybe; - - domain?: Maybe; - - geo?: Maybe; - - packets?: Maybe; -} - -export interface GeoEcsFields { - city_name?: Maybe; - - continent_name?: Maybe; - - country_iso_code?: Maybe; - - country_name?: Maybe; - - location?: Maybe; - - region_iso_code?: Maybe; - - region_name?: Maybe; -} - -export interface Location { - lon?: Maybe; - - lat?: Maybe; -} - -export interface HostEcsFields { - architecture?: Maybe; - - id?: Maybe; - - ip?: Maybe; - - mac?: Maybe; - - name?: Maybe; - - os?: Maybe; - - type?: Maybe; -} - -export interface OsEcsFields { - platform?: Maybe; - - name?: Maybe; - - full?: Maybe; - - family?: Maybe; - - version?: Maybe; - - kernel?: Maybe; -} - -export interface CursorType { - value?: Maybe; - - tiebreaker?: Maybe; -} - -export interface PageInfoPaginated { - activePage: number; - - fakeTotalCount: number; - - showMorePagesIndicator: boolean; -} - -export interface Inspect { - dsl: string[]; - - response: string[]; -} - -export interface TimelineData { - edges: TimelineEdges[]; - - totalCount: number; - - pageInfo: PageInfo; - - inspect?: Maybe; -} - -export interface TimelineEdges { - node: TimelineItem; - - cursor: CursorType; -} - -export interface TimelineItem { - _id: string; - - _index?: Maybe; - - data: TimelineNonEcsData[]; - - ecs: Ecs; -} - -export interface TimelineNonEcsData { - field: string; - - value?: Maybe; -} - -export interface Ecs { - _id: string; - - _index?: Maybe; - - auditd?: Maybe; - - destination?: Maybe; - - dns?: Maybe; - - endgame?: Maybe; - - event?: Maybe; - - geo?: Maybe; - - host?: Maybe; - - network?: Maybe; - - rule?: Maybe; - - signal?: Maybe; - - source?: Maybe; - - suricata?: Maybe; - - tls?: Maybe; - - zeek?: Maybe; - - http?: Maybe; - - url?: Maybe; - - timestamp?: Maybe; - - message?: Maybe; - - user?: Maybe; - - winlog?: Maybe; - - process?: Maybe; - - file?: Maybe; - - system?: Maybe; -} - -export interface AuditdEcsFields { - result?: Maybe; - - session?: Maybe; - - data?: Maybe; - - summary?: Maybe; - - sequence?: Maybe; -} - -export interface AuditdData { - acct?: Maybe; - - terminal?: Maybe; - - op?: Maybe; -} - -export interface Summary { - actor?: Maybe; - - object?: Maybe; - - how?: Maybe; - - message_type?: Maybe; - - sequence?: Maybe; -} - -export interface PrimarySecondary { - primary?: Maybe; - - secondary?: Maybe; - - type?: Maybe; -} - -export interface DestinationEcsFields { - bytes?: Maybe; - - ip?: Maybe; - - port?: Maybe; - - domain?: Maybe; - - geo?: Maybe; - - packets?: Maybe; -} - -export interface DnsEcsFields { - question?: Maybe; - - resolved_ip?: Maybe; - - response_code?: Maybe; -} - -export interface DnsQuestionData { - name?: Maybe; - - type?: Maybe; -} - -export interface EndgameEcsFields { - exit_code?: Maybe; - - file_name?: Maybe; - - file_path?: Maybe; - - logon_type?: Maybe; - - parent_process_name?: Maybe; - - pid?: Maybe; - - process_name?: Maybe; - - subject_domain_name?: Maybe; - - subject_logon_id?: Maybe; - - subject_user_name?: Maybe; - - target_domain_name?: Maybe; - - target_logon_id?: Maybe; - - target_user_name?: Maybe; -} - -export interface EventEcsFields { - action?: Maybe; - - category?: Maybe; - - code?: Maybe; - - created?: Maybe; - - dataset?: Maybe; - - duration?: Maybe; - - end?: Maybe; - - hash?: Maybe; - - id?: Maybe; - - kind?: Maybe; - - module?: Maybe; - - original?: Maybe; - - outcome?: Maybe; - - risk_score?: Maybe; - - risk_score_norm?: Maybe; - - severity?: Maybe; - - start?: Maybe; - - timezone?: Maybe; - - type?: Maybe; -} - -export interface NetworkEcsField { - bytes?: Maybe; - - community_id?: Maybe; - - direction?: Maybe; - - packets?: Maybe; - - protocol?: Maybe; - - transport?: Maybe; -} - -export interface RuleEcsField { - reference?: Maybe; -} - -export interface SignalField { - rule?: Maybe; - - original_time?: Maybe; -} - -export interface RuleField { - id?: Maybe; - - rule_id?: Maybe; - - false_positives: string[]; - - saved_id?: Maybe; - - timeline_id?: Maybe; - - timeline_title?: Maybe; - - max_signals?: Maybe; - - risk_score?: Maybe; - - output_index?: Maybe; - - description?: Maybe; - - from?: Maybe; - - immutable?: Maybe; - - index?: Maybe; - - interval?: Maybe; - - language?: Maybe; - - query?: Maybe; - - references?: Maybe; - - severity?: Maybe; - - tags?: Maybe; - - threat?: Maybe; - - type?: Maybe; - - size?: Maybe; - - to?: Maybe; - - enabled?: Maybe; - - filters?: Maybe; - - created_at?: Maybe; - - updated_at?: Maybe; - - created_by?: Maybe; - - updated_by?: Maybe; - - version?: Maybe; -} - -export interface SuricataEcsFields { - eve?: Maybe; -} - -export interface SuricataEveData { - alert?: Maybe; - - flow_id?: Maybe; - - proto?: Maybe; -} - -export interface SuricataAlertData { - signature?: Maybe; - - signature_id?: Maybe; -} - -export interface TlsEcsFields { - client_certificate?: Maybe; - - fingerprints?: Maybe; - - server_certificate?: Maybe; -} - -export interface TlsClientCertificateData { - fingerprint?: Maybe; -} - -export interface FingerprintData { - sha1?: Maybe; -} - -export interface TlsFingerprintsData { - ja3?: Maybe; -} - -export interface TlsJa3Data { - hash?: Maybe; -} - -export interface TlsServerCertificateData { - fingerprint?: Maybe; -} - -export interface ZeekEcsFields { - session_id?: Maybe; - - connection?: Maybe; - - notice?: Maybe; - - dns?: Maybe; - - http?: Maybe; - - files?: Maybe; - - ssl?: Maybe; -} - -export interface ZeekConnectionData { - local_resp?: Maybe; - - local_orig?: Maybe; - - missed_bytes?: Maybe; - - state?: Maybe; - - history?: Maybe; -} - -export interface ZeekNoticeData { - suppress_for?: Maybe; - - msg?: Maybe; - - note?: Maybe; - - sub?: Maybe; - - dst?: Maybe; - - dropped?: Maybe; - - peer_descr?: Maybe; -} - -export interface ZeekDnsData { - AA?: Maybe; - - qclass_name?: Maybe; - - RD?: Maybe; - - qtype_name?: Maybe; - - rejected?: Maybe; - - qtype?: Maybe; - - query?: Maybe; - - trans_id?: Maybe; - - qclass?: Maybe; - - RA?: Maybe; - - TC?: Maybe; -} - -export interface ZeekHttpData { - resp_mime_types?: Maybe; - - trans_depth?: Maybe; - - status_msg?: Maybe; - - resp_fuids?: Maybe; - - tags?: Maybe; -} - -export interface ZeekFileData { - session_ids?: Maybe; - - timedout?: Maybe; - - local_orig?: Maybe; - - tx_host?: Maybe; - - source?: Maybe; - - is_orig?: Maybe; - - overflow_bytes?: Maybe; - - sha1?: Maybe; - - duration?: Maybe; - - depth?: Maybe; - - analyzers?: Maybe; - - mime_type?: Maybe; - - rx_host?: Maybe; - - total_bytes?: Maybe; - - fuid?: Maybe; - - seen_bytes?: Maybe; - - missing_bytes?: Maybe; - - md5?: Maybe; -} - -export interface ZeekSslData { - cipher?: Maybe; - - established?: Maybe; - - resumed?: Maybe; - - version?: Maybe; -} - -export interface HttpEcsFields { - version?: Maybe; - - request?: Maybe; - - response?: Maybe; -} - -export interface HttpRequestData { - method?: Maybe; - - body?: Maybe; - - referrer?: Maybe; - - bytes?: Maybe; -} - -export interface HttpBodyData { - content?: Maybe; - - bytes?: Maybe; -} - -export interface HttpResponseData { - status_code?: Maybe; - - body?: Maybe; - - bytes?: Maybe; -} - -export interface UrlEcsFields { - domain?: Maybe; - - original?: Maybe; - - username?: Maybe; - - password?: Maybe; -} - -export interface WinlogEcsFields { - event_id?: Maybe; -} - -export interface ProcessEcsFields { - hash?: Maybe; - - pid?: Maybe; - - name?: Maybe; - - ppid?: Maybe; - - args?: Maybe; - - executable?: Maybe; - - title?: Maybe; - - thread?: Maybe; - - working_directory?: Maybe; -} - -export interface ProcessHashData { - md5?: Maybe; - - sha1?: Maybe; - - sha256?: Maybe; -} - -export interface Thread { - id?: Maybe; - - start?: Maybe; -} - -export interface FileFields { - name?: Maybe; - - path?: Maybe; - - target_path?: Maybe; - - extension?: Maybe; - - type?: Maybe; - - device?: Maybe; - - inode?: Maybe; - - uid?: Maybe; - - owner?: Maybe; - - gid?: Maybe; - - group?: Maybe; - - mode?: Maybe; - - size?: Maybe; - - mtime?: Maybe; - - ctime?: Maybe; -} - -export interface SystemEcsField { - audit?: Maybe; - - auth?: Maybe; -} - -export interface AuditEcsFields { - package?: Maybe; -} - -export interface PackageEcsFields { - arch?: Maybe; - - entity_id?: Maybe; - - name?: Maybe; - - size?: Maybe; - - summary?: Maybe; - - version?: Maybe; -} - -export interface AuthEcsFields { - ssh?: Maybe; -} - -export interface SshEcsFields { - method?: Maybe; - - signature?: Maybe; -} - -export interface PageInfo { - endCursor?: Maybe; - - hasNextPage?: Maybe; -} - -export interface TimelineDetailsData { - data?: Maybe; - - inspect?: Maybe; -} - -export interface DetailItem { - field: string; - - values?: Maybe; - - originalValue?: Maybe; -} - -export interface LastEventTimeData { - lastSeen?: Maybe; - - inspect?: Maybe; -} - -export interface HostsData { - edges: HostsEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface HostsEdges { - node: HostItem; - - cursor: CursorType; -} - -export interface HostItem { - _id?: Maybe; - - lastSeen?: Maybe; - - host?: Maybe; - - cloud?: Maybe; - - inspect?: Maybe; -} - -export interface CloudFields { - instance?: Maybe; - - machine?: Maybe; - - provider?: Maybe<(Maybe)[]>; - - region?: Maybe<(Maybe)[]>; -} - -export interface CloudInstance { - id?: Maybe<(Maybe)[]>; -} - -export interface CloudMachine { - type?: Maybe<(Maybe)[]>; -} - -export interface FirstLastSeenHost { - inspect?: Maybe; - - firstSeen?: Maybe; - - lastSeen?: Maybe; -} - -export interface IpOverviewData { - client?: Maybe; - - destination?: Maybe; - - host: HostEcsFields; - - server?: Maybe; - - source?: Maybe; - - inspect?: Maybe; -} - -export interface Overview { - firstSeen?: Maybe; - - lastSeen?: Maybe; - - autonomousSystem: AutonomousSystem; - - geo: GeoEcsFields; -} - -export interface AutonomousSystem { - number?: Maybe; - - organization?: Maybe; -} - -export interface AutonomousSystemOrganization { - name?: Maybe; -} - -export interface UsersData { - edges: UsersEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface UsersEdges { - node: UsersNode; - - cursor: CursorType; -} - -export interface UsersNode { - _id?: Maybe; - - timestamp?: Maybe; - - user?: Maybe; -} - -export interface UsersItem { - name?: Maybe; - - id?: Maybe; - - groupId?: Maybe; - - groupName?: Maybe; - - count?: Maybe; -} - -export interface KpiNetworkData { - networkEvents?: Maybe; - - uniqueFlowId?: Maybe; - - uniqueSourcePrivateIps?: Maybe; - - uniqueSourcePrivateIpsHistogram?: Maybe; - - uniqueDestinationPrivateIps?: Maybe; - - uniqueDestinationPrivateIpsHistogram?: Maybe; - - dnsQueries?: Maybe; - - tlsHandshakes?: Maybe; - - inspect?: Maybe; -} - -export interface KpiNetworkHistogramData { - x?: Maybe; - - y?: Maybe; -} - -export interface KpiHostsData { - hosts?: Maybe; - - hostsHistogram?: Maybe; - - authSuccess?: Maybe; - - authSuccessHistogram?: Maybe; - - authFailure?: Maybe; - - authFailureHistogram?: Maybe; - - uniqueSourceIps?: Maybe; - - uniqueSourceIpsHistogram?: Maybe; - - uniqueDestinationIps?: Maybe; - - uniqueDestinationIpsHistogram?: Maybe; - - inspect?: Maybe; -} - -export interface KpiHostHistogramData { - x?: Maybe; - - y?: Maybe; -} - -export interface KpiHostDetailsData { - authSuccess?: Maybe; - - authSuccessHistogram?: Maybe; - - authFailure?: Maybe; - - authFailureHistogram?: Maybe; - - uniqueSourceIps?: Maybe; - - uniqueSourceIpsHistogram?: Maybe; - - uniqueDestinationIps?: Maybe; - - uniqueDestinationIpsHistogram?: Maybe; - - inspect?: Maybe; -} - -export interface MatrixHistogramOverTimeData { - inspect?: Maybe; - - matrixHistogramData: MatrixOverTimeHistogramData[]; - - totalCount: number; -} - -export interface MatrixOverTimeHistogramData { - x?: Maybe; - - y?: Maybe; - - g?: Maybe; -} - -export interface NetworkTopCountriesData { - edges: NetworkTopCountriesEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface NetworkTopCountriesEdges { - node: NetworkTopCountriesItem; - - cursor: CursorType; -} - -export interface NetworkTopCountriesItem { - _id?: Maybe; - - source?: Maybe; - - destination?: Maybe; - - network?: Maybe; -} - -export interface TopCountriesItemSource { - country?: Maybe; - - destination_ips?: Maybe; - - flows?: Maybe; - - location?: Maybe; - - source_ips?: Maybe; -} - -export interface GeoItem { - geo?: Maybe; - - flowTarget?: Maybe; -} - -export interface TopCountriesItemDestination { - country?: Maybe; - - destination_ips?: Maybe; - - flows?: Maybe; - - location?: Maybe; - - source_ips?: Maybe; -} - -export interface TopNetworkTablesEcsField { - bytes_in?: Maybe; - - bytes_out?: Maybe; -} - -export interface NetworkTopNFlowData { - edges: NetworkTopNFlowEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface NetworkTopNFlowEdges { - node: NetworkTopNFlowItem; - - cursor: CursorType; -} - -export interface NetworkTopNFlowItem { - _id?: Maybe; - - source?: Maybe; - - destination?: Maybe; - - network?: Maybe; -} - -export interface TopNFlowItemSource { - autonomous_system?: Maybe; - - domain?: Maybe; - - ip?: Maybe; - - location?: Maybe; - - flows?: Maybe; - - destination_ips?: Maybe; -} - -export interface AutonomousSystemItem { - name?: Maybe; - - number?: Maybe; -} - -export interface TopNFlowItemDestination { - autonomous_system?: Maybe; - - domain?: Maybe; - - ip?: Maybe; - - location?: Maybe; - - flows?: Maybe; - - source_ips?: Maybe; -} - -export interface NetworkDnsData { - edges: NetworkDnsEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; - - histogram?: Maybe; -} - -export interface NetworkDnsEdges { - node: NetworkDnsItem; - - cursor: CursorType; -} - -export interface NetworkDnsItem { - _id?: Maybe; - - dnsBytesIn?: Maybe; - - dnsBytesOut?: Maybe; - - dnsName?: Maybe; - - queryCount?: Maybe; - - uniqueDomains?: Maybe; -} - -export interface MatrixOverOrdinalHistogramData { - x: string; - - y: number; - - g: string; -} - -export interface NetworkDsOverTimeData { - inspect?: Maybe; - - matrixHistogramData: MatrixOverTimeHistogramData[]; - - totalCount: number; -} - -export interface NetworkHttpData { - edges: NetworkHttpEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface NetworkHttpEdges { - node: NetworkHttpItem; - - cursor: CursorType; -} - -export interface NetworkHttpItem { - _id?: Maybe; - - domains: string[]; - - lastHost?: Maybe; - - lastSourceIp?: Maybe; - - methods: string[]; - - path?: Maybe; - - requestCount?: Maybe; - - statuses: string[]; -} - -export interface OverviewNetworkData { - auditbeatSocket?: Maybe; - - filebeatCisco?: Maybe; - - filebeatNetflow?: Maybe; - - filebeatPanw?: Maybe; - - filebeatSuricata?: Maybe; - - filebeatZeek?: Maybe; - - packetbeatDNS?: Maybe; - - packetbeatFlow?: Maybe; - - packetbeatTLS?: Maybe; - - inspect?: Maybe; -} - -export interface OverviewHostData { - auditbeatAuditd?: Maybe; - - auditbeatFIM?: Maybe; - - auditbeatLogin?: Maybe; - - auditbeatPackage?: Maybe; - - auditbeatProcess?: Maybe; - - auditbeatUser?: Maybe; - - endgameDns?: Maybe; - - endgameFile?: Maybe; - - endgameImageLoad?: Maybe; - - endgameNetwork?: Maybe; - - endgameProcess?: Maybe; - - endgameRegistry?: Maybe; - - endgameSecurity?: Maybe; - - filebeatSystemModule?: Maybe; - - winlogbeatSecurity?: Maybe; - - winlogbeatMWSysmonOperational?: Maybe; - - inspect?: Maybe; -} - -export interface TlsData { - edges: TlsEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface TlsEdges { - node: TlsNode; - - cursor: CursorType; -} - -export interface TlsNode { - _id?: Maybe; - - timestamp?: Maybe; - - alternativeNames?: Maybe; - - notAfter?: Maybe; - - commonNames?: Maybe; - - ja3?: Maybe; - - issuerNames?: Maybe; -} - -export interface UncommonProcessesData { - edges: UncommonProcessesEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface UncommonProcessesEdges { - node: UncommonProcessItem; - - cursor: CursorType; -} - -export interface UncommonProcessItem { - _id: string; - - instances: number; - - process: ProcessEcsFields; - - hosts: HostEcsFields[]; - - user?: Maybe; -} - -export interface SayMyName { - /** The id of the source */ - appName: string; -} - -export interface TimelineResult { - columns?: Maybe; - - created?: Maybe; - - createdBy?: Maybe; - - dataProviders?: Maybe; - - dateRange?: Maybe; - - description?: Maybe; - - eventIdToNoteIds?: Maybe; - - eventType?: Maybe; - - favorite?: Maybe; - - filters?: Maybe; - - kqlMode?: Maybe; - - kqlQuery?: Maybe; - - notes?: Maybe; - - noteIds?: Maybe; - - pinnedEventIds?: Maybe; - - pinnedEventsSaveObject?: Maybe; - - savedQueryId?: Maybe; - - savedObjectId: string; - - sort?: Maybe; - - title?: Maybe; - - updated?: Maybe; - - updatedBy?: Maybe; - - version: string; -} - -export interface ColumnHeaderResult { - aggregatable?: Maybe; - - category?: Maybe; - - columnHeaderType?: Maybe; - - description?: Maybe; - - example?: Maybe; - - indexes?: Maybe; - - id?: Maybe; - - name?: Maybe; - - placeholder?: Maybe; - - searchable?: Maybe; - - type?: Maybe; -} - -export interface DataProviderResult { - id?: Maybe; - - name?: Maybe; - - enabled?: Maybe; - - excluded?: Maybe; - - kqlQuery?: Maybe; - - queryMatch?: Maybe; - - and?: Maybe; -} - -export interface QueryMatchResult { - field?: Maybe; - - displayField?: Maybe; - - value?: Maybe; - - displayValue?: Maybe; - - operator?: Maybe; -} - -export interface DateRangePickerResult { - start?: Maybe; - - end?: Maybe; -} - -export interface FavoriteTimelineResult { - fullName?: Maybe; - - userName?: Maybe; - - favoriteDate?: Maybe; -} - -export interface FilterTimelineResult { - exists?: Maybe; - - meta?: Maybe; - - match_all?: Maybe; - - missing?: Maybe; - - query?: Maybe; - - range?: Maybe; - - script?: Maybe; -} - -export interface FilterMetaTimelineResult { - alias?: Maybe; - - controlledBy?: Maybe; - - disabled?: Maybe; - - field?: Maybe; - - formattedValue?: Maybe; - - index?: Maybe; - - key?: Maybe; - - negate?: Maybe; - - params?: Maybe; - - type?: Maybe; - - value?: Maybe; -} - -export interface SerializedFilterQueryResult { - filterQuery?: Maybe; -} - -export interface SerializedKueryQueryResult { - kuery?: Maybe; - - serializedQuery?: Maybe; -} - -export interface KueryFilterQueryResult { - kind?: Maybe; - - expression?: Maybe; -} - -export interface SortTimelineResult { - columnId?: Maybe; - - sortDirection?: Maybe; -} - -export interface ResponseTimelines { - timeline: (Maybe)[]; - - totalCount?: Maybe; -} - -export interface Mutation { - /** Persists a note */ - persistNote: ResponseNote; - - deleteNote?: Maybe; - - deleteNoteByTimelineId?: Maybe; - /** Persists a pinned event in a timeline */ - persistPinnedEventOnTimeline?: Maybe; - /** Remove a pinned events in a timeline */ - deletePinnedEventOnTimeline: boolean; - /** Remove all pinned events in a timeline */ - deleteAllPinnedEventsOnTimeline: boolean; - /** Persists a timeline */ - persistTimeline: ResponseTimeline; - - persistFavorite: ResponseFavoriteTimeline; - - deleteTimeline: boolean; -} - -export interface ResponseNote { - code?: Maybe; - - message?: Maybe; - - note: NoteResult; -} - -export interface ResponseTimeline { - code?: Maybe; - - message?: Maybe; - - timeline: TimelineResult; -} - -export interface ResponseFavoriteTimeline { - code?: Maybe; - - message?: Maybe; - - savedObjectId: string; - - version: string; - - favorite?: Maybe; -} - -export interface EcsEdges { - node: Ecs; - - cursor: CursorType; -} - -export interface EventsTimelineData { - edges: EcsEdges[]; - - totalCount: number; - - pageInfo: PageInfo; - - inspect?: Maybe; -} - -export interface OsFields { - platform?: Maybe; - - name?: Maybe; - - full?: Maybe; - - family?: Maybe; - - version?: Maybe; - - kernel?: Maybe; -} - -export interface HostFields { - architecture?: Maybe; - - id?: Maybe; - - ip?: Maybe<(Maybe)[]>; - - mac?: Maybe<(Maybe)[]>; - - name?: Maybe; - - os?: Maybe; - - type?: Maybe; -} - -// ==================================================== -// Arguments -// ==================================================== - -export interface GetNoteQueryArgs { - id: string; -} -export interface GetNotesByTimelineIdQueryArgs { - timelineId: string; -} -export interface GetNotesByEventIdQueryArgs { - eventId: string; -} -export interface GetAllNotesQueryArgs { - pageInfo?: Maybe; - - search?: Maybe; - - sort?: Maybe; -} -export interface GetAllPinnedEventsByTimelineIdQueryArgs { - timelineId: string; -} -export interface SourceQueryArgs { - /** The id of the source */ - id: string; -} -export interface GetOneTimelineQueryArgs { - id: string; -} -export interface GetAllTimelineQueryArgs { - pageInfo?: Maybe; - - search?: Maybe; - - sort?: Maybe; - - onlyUserFavorite?: Maybe; -} -export interface AuthenticationsSourceArgs { - timerange: TimerangeInput; - - pagination: PaginationInputPaginated; - - filterQuery?: Maybe; - - defaultIndex: string[]; -} -export interface TimelineSourceArgs { - pagination: PaginationInput; - - sortField: SortField; - - fieldRequested: string[]; - - timerange?: Maybe; - - filterQuery?: Maybe; - - defaultIndex: string[]; -} -export interface TimelineDetailsSourceArgs { - eventId: string; - - indexName: string; - - defaultIndex: string[]; -} -export interface LastEventTimeSourceArgs { - id?: Maybe; - - indexKey: LastEventIndexKey; - - details: LastTimeDetails; - - defaultIndex: string[]; -} -export interface HostsSourceArgs { - id?: Maybe; - - timerange: TimerangeInput; - - pagination: PaginationInputPaginated; - - sort: HostsSortField; - - filterQuery?: Maybe; - - defaultIndex: string[]; -} -export interface HostOverviewSourceArgs { - id?: Maybe; - - hostName: string; - - timerange: TimerangeInput; - - defaultIndex: string[]; -} -export interface HostFirstLastSeenSourceArgs { - id?: Maybe; - - hostName: string; - - defaultIndex: string[]; -} -export interface IpOverviewSourceArgs { - id?: Maybe; - - filterQuery?: Maybe; - - ip: string; - - defaultIndex: string[]; -} -export interface UsersSourceArgs { - filterQuery?: Maybe; - - id?: Maybe; - - ip: string; - - pagination: PaginationInputPaginated; - - sort: UsersSortField; - - flowTarget: FlowTarget; - - timerange: TimerangeInput; - - defaultIndex: string[]; -} -export interface KpiNetworkSourceArgs { - id?: Maybe; - - timerange: TimerangeInput; - - filterQuery?: Maybe; - - defaultIndex: string[]; -} -export interface KpiHostsSourceArgs { - id?: Maybe; - - timerange: TimerangeInput; - - filterQuery?: Maybe; - - defaultIndex: string[]; -} -export interface KpiHostDetailsSourceArgs { - id?: Maybe; - - timerange: TimerangeInput; - - filterQuery?: Maybe; - - defaultIndex: string[]; -} -export interface MatrixHistogramSourceArgs { - filterQuery?: Maybe; - - defaultIndex: string[]; - - timerange: TimerangeInput; - - stackByField: string; - - histogramType: HistogramType; -} -export interface NetworkTopCountriesSourceArgs { - id?: Maybe; - - filterQuery?: Maybe; - - ip?: Maybe; - - flowTarget: FlowTargetSourceDest; - - pagination: PaginationInputPaginated; - - sort: NetworkTopTablesSortField; - - timerange: TimerangeInput; - - defaultIndex: string[]; -} -export interface NetworkTopNFlowSourceArgs { - id?: Maybe; - - filterQuery?: Maybe; - - ip?: Maybe; - - flowTarget: FlowTargetSourceDest; - - pagination: PaginationInputPaginated; - - sort: NetworkTopTablesSortField; - - timerange: TimerangeInput; - - defaultIndex: string[]; -} -export interface NetworkDnsSourceArgs { - filterQuery?: Maybe; - - id?: Maybe; - - isPtrIncluded: boolean; - - pagination: PaginationInputPaginated; - - sort: NetworkDnsSortField; - - stackByField?: Maybe; - - timerange: TimerangeInput; - - defaultIndex: string[]; -} -export interface NetworkDnsHistogramSourceArgs { - filterQuery?: Maybe; - - defaultIndex: string[]; - - timerange: TimerangeInput; - - stackByField?: Maybe; -} -export interface NetworkHttpSourceArgs { - id?: Maybe; - - filterQuery?: Maybe; - - ip?: Maybe; - - pagination: PaginationInputPaginated; - - sort: NetworkHttpSortField; - - timerange: TimerangeInput; - - defaultIndex: string[]; -} -export interface OverviewNetworkSourceArgs { - id?: Maybe; - - timerange: TimerangeInput; - - filterQuery?: Maybe; - - defaultIndex: string[]; -} -export interface OverviewHostSourceArgs { - id?: Maybe; - - timerange: TimerangeInput; - - filterQuery?: Maybe; - - defaultIndex: string[]; -} -export interface TlsSourceArgs { - filterQuery?: Maybe; - - id?: Maybe; - - ip: string; - - pagination: PaginationInputPaginated; - - sort: TlsSortField; - - flowTarget: FlowTargetSourceDest; - - timerange: TimerangeInput; - - defaultIndex: string[]; -} -export interface UncommonProcessesSourceArgs { - timerange: TimerangeInput; - - pagination: PaginationInputPaginated; - - filterQuery?: Maybe; - - defaultIndex: string[]; -} -export interface IndicesExistSourceStatusArgs { - defaultIndex: string[]; -} -export interface IndexFieldsSourceStatusArgs { - defaultIndex: string[]; -} -export interface PersistNoteMutationArgs { - noteId?: Maybe; - - version?: Maybe; - - note: NoteInput; -} -export interface DeleteNoteMutationArgs { - id: string[]; -} -export interface DeleteNoteByTimelineIdMutationArgs { - timelineId: string; - - version?: Maybe; -} -export interface PersistPinnedEventOnTimelineMutationArgs { - pinnedEventId?: Maybe; - - eventId: string; - - timelineId?: Maybe; -} -export interface DeletePinnedEventOnTimelineMutationArgs { - id: string[]; -} -export interface DeleteAllPinnedEventsOnTimelineMutationArgs { - timelineId: string; -} -export interface PersistTimelineMutationArgs { - id?: Maybe; - - version?: Maybe; - - timeline: TimelineInput; -} -export interface PersistFavoriteMutationArgs { - timelineId?: Maybe; -} -export interface DeleteTimelineMutationArgs { - id: string[]; -} - -// ==================================================== -// Documents -// ==================================================== - -export namespace GetAuthenticationsQuery { - export type Variables = { - sourceId: string; - timerange: TimerangeInput; - pagination: PaginationInputPaginated; - filterQuery?: Maybe; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - Authentications: Authentications; - }; - - export type Authentications = { - __typename?: 'AuthenticationsData'; - - totalCount: number; - - edges: Edges[]; - - pageInfo: PageInfo; - - inspect: Maybe; - }; - - export type Edges = { - __typename?: 'AuthenticationsEdges'; - - node: Node; - - cursor: Cursor; - }; - - export type Node = { - __typename?: 'AuthenticationItem'; - - _id: string; - - failures: number; - - successes: number; - - user: User; - - lastSuccess: Maybe; - - lastFailure: Maybe; - }; - - export type User = { - __typename?: 'UserEcsFields'; - - name: Maybe; - }; - - export type LastSuccess = { - __typename?: 'LastSourceHost'; - - timestamp: Maybe; - - source: Maybe<_Source>; - - host: Maybe; - }; - - export type _Source = { - __typename?: 'SourceEcsFields'; - - ip: Maybe; - }; - - export type Host = { - __typename?: 'HostEcsFields'; - - id: Maybe; - - name: Maybe; - }; - - export type LastFailure = { - __typename?: 'LastSourceHost'; - - timestamp: Maybe; - - source: Maybe<__Source>; - - host: Maybe<_Host>; - }; - - export type __Source = { - __typename?: 'SourceEcsFields'; - - ip: Maybe; - }; - - export type _Host = { - __typename?: 'HostEcsFields'; - - id: Maybe; - - name: Maybe; - }; - - export type Cursor = { - __typename?: 'CursorType'; - - value: Maybe; - }; - - export type PageInfo = { - __typename?: 'PageInfoPaginated'; - - activePage: number; - - fakeTotalCount: number; - - showMorePagesIndicator: boolean; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetLastEventTimeQuery { - export type Variables = { - sourceId: string; - indexKey: LastEventIndexKey; - details: LastTimeDetails; - defaultIndex: string[]; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - LastEventTime: LastEventTime; - }; - - export type LastEventTime = { - __typename?: 'LastEventTimeData'; - - lastSeen: Maybe; - }; -} - -export namespace GetHostFirstLastSeenQuery { - export type Variables = { - sourceId: string; - hostName: string; - defaultIndex: string[]; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - HostFirstLastSeen: HostFirstLastSeen; - }; - - export type HostFirstLastSeen = { - __typename?: 'FirstLastSeenHost'; - - firstSeen: Maybe; - - lastSeen: Maybe; - }; -} - -export namespace GetHostsTableQuery { - export type Variables = { - sourceId: string; - timerange: TimerangeInput; - pagination: PaginationInputPaginated; - sort: HostsSortField; - filterQuery?: Maybe; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - Hosts: Hosts; - }; - - export type Hosts = { - __typename?: 'HostsData'; - - totalCount: number; - - edges: Edges[]; - - pageInfo: PageInfo; - - inspect: Maybe; - }; - - export type Edges = { - __typename?: 'HostsEdges'; - - node: Node; - - cursor: Cursor; - }; - - export type Node = { - __typename?: 'HostItem'; - - _id: Maybe; - - lastSeen: Maybe; - - host: Maybe; - }; - - export type Host = { - __typename?: 'HostEcsFields'; - - id: Maybe; - - name: Maybe; - - os: Maybe; - }; - - export type Os = { - __typename?: 'OsEcsFields'; - - name: Maybe; - - version: Maybe; - }; - - export type Cursor = { - __typename?: 'CursorType'; - - value: Maybe; - }; - - export type PageInfo = { - __typename?: 'PageInfoPaginated'; - - activePage: number; - - fakeTotalCount: number; - - showMorePagesIndicator: boolean; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetHostOverviewQuery { - export type Variables = { - sourceId: string; - hostName: string; - timerange: TimerangeInput; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - HostOverview: HostOverview; - }; - - export type HostOverview = { - __typename?: 'HostItem'; - - _id: Maybe; - - host: Maybe; - - cloud: Maybe; - - inspect: Maybe; - }; - - export type Host = { - __typename?: 'HostEcsFields'; - - architecture: Maybe; - - id: Maybe; - - ip: Maybe; - - mac: Maybe; - - name: Maybe; - - os: Maybe; - - type: Maybe; - }; - - export type Os = { - __typename?: 'OsEcsFields'; - - family: Maybe; - - name: Maybe; - - platform: Maybe; - - version: Maybe; - }; - - export type Cloud = { - __typename?: 'CloudFields'; - - instance: Maybe; - - machine: Maybe; - - provider: Maybe<(Maybe)[]>; - - region: Maybe<(Maybe)[]>; - }; - - export type Instance = { - __typename?: 'CloudInstance'; - - id: Maybe<(Maybe)[]>; - }; - - export type Machine = { - __typename?: 'CloudMachine'; - - type: Maybe<(Maybe)[]>; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetIpOverviewQuery { - export type Variables = { - sourceId: string; - filterQuery?: Maybe; - ip: string; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - IpOverview: Maybe; - }; - - export type IpOverview = { - __typename?: 'IpOverviewData'; - - source: Maybe<_Source>; - - destination: Maybe; - - host: Host; - - inspect: Maybe; - }; - - export type _Source = { - __typename?: 'Overview'; - - firstSeen: Maybe; - - lastSeen: Maybe; - - autonomousSystem: AutonomousSystem; - - geo: Geo; - }; - - export type AutonomousSystem = { - __typename?: 'AutonomousSystem'; - - number: Maybe; - - organization: Maybe; - }; - - export type Organization = { - __typename?: 'AutonomousSystemOrganization'; - - name: Maybe; - }; - - export type Geo = { - __typename?: 'GeoEcsFields'; - - continent_name: Maybe; - - city_name: Maybe; - - country_iso_code: Maybe; - - country_name: Maybe; - - location: Maybe; - - region_iso_code: Maybe; - - region_name: Maybe; - }; - - export type Location = { - __typename?: 'Location'; - - lat: Maybe; - - lon: Maybe; - }; - - export type Destination = { - __typename?: 'Overview'; - - firstSeen: Maybe; - - lastSeen: Maybe; - - autonomousSystem: _AutonomousSystem; - - geo: _Geo; - }; - - export type _AutonomousSystem = { - __typename?: 'AutonomousSystem'; - - number: Maybe; - - organization: Maybe<_Organization>; - }; - - export type _Organization = { - __typename?: 'AutonomousSystemOrganization'; - - name: Maybe; - }; - - export type _Geo = { - __typename?: 'GeoEcsFields'; - - continent_name: Maybe; - - city_name: Maybe; - - country_iso_code: Maybe; - - country_name: Maybe; - - location: Maybe<_Location>; - - region_iso_code: Maybe; - - region_name: Maybe; - }; - - export type _Location = { - __typename?: 'Location'; - - lat: Maybe; - - lon: Maybe; - }; - - export type Host = { - __typename?: 'HostEcsFields'; - - architecture: Maybe; - - id: Maybe; - - ip: Maybe; - - mac: Maybe; - - name: Maybe; - - os: Maybe; - - type: Maybe; - }; - - export type Os = { - __typename?: 'OsEcsFields'; - - family: Maybe; - - name: Maybe; - - platform: Maybe; - - version: Maybe; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetKpiHostDetailsQuery { - export type Variables = { - sourceId: string; - timerange: TimerangeInput; - filterQuery?: Maybe; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - KpiHostDetails: KpiHostDetails; - }; - - export type KpiHostDetails = { - __typename?: 'KpiHostDetailsData'; - - authSuccess: Maybe; - - authSuccessHistogram: Maybe; - - authFailure: Maybe; - - authFailureHistogram: Maybe; - - uniqueSourceIps: Maybe; - - uniqueSourceIpsHistogram: Maybe; - - uniqueDestinationIps: Maybe; - - uniqueDestinationIpsHistogram: Maybe; - - inspect: Maybe; - }; - - export type AuthSuccessHistogram = KpiHostDetailsChartFields.Fragment; - - export type AuthFailureHistogram = KpiHostDetailsChartFields.Fragment; - - export type UniqueSourceIpsHistogram = KpiHostDetailsChartFields.Fragment; - - export type UniqueDestinationIpsHistogram = KpiHostDetailsChartFields.Fragment; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetKpiHostsQuery { - export type Variables = { - sourceId: string; - timerange: TimerangeInput; - filterQuery?: Maybe; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - KpiHosts: KpiHosts; - }; - - export type KpiHosts = { - __typename?: 'KpiHostsData'; - - hosts: Maybe; - - hostsHistogram: Maybe; - - authSuccess: Maybe; - - authSuccessHistogram: Maybe; - - authFailure: Maybe; - - authFailureHistogram: Maybe; - - uniqueSourceIps: Maybe; - - uniqueSourceIpsHistogram: Maybe; - - uniqueDestinationIps: Maybe; - - uniqueDestinationIpsHistogram: Maybe; - - inspect: Maybe; - }; - - export type HostsHistogram = KpiHostChartFields.Fragment; - - export type AuthSuccessHistogram = KpiHostChartFields.Fragment; - - export type AuthFailureHistogram = KpiHostChartFields.Fragment; - - export type UniqueSourceIpsHistogram = KpiHostChartFields.Fragment; - - export type UniqueDestinationIpsHistogram = KpiHostChartFields.Fragment; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetKpiNetworkQuery { - export type Variables = { - sourceId: string; - timerange: TimerangeInput; - filterQuery?: Maybe; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - KpiNetwork: Maybe; - }; - - export type KpiNetwork = { - __typename?: 'KpiNetworkData'; - - networkEvents: Maybe; - - uniqueFlowId: Maybe; - - uniqueSourcePrivateIps: Maybe; - - uniqueSourcePrivateIpsHistogram: Maybe; - - uniqueDestinationPrivateIps: Maybe; - - uniqueDestinationPrivateIpsHistogram: Maybe; - - dnsQueries: Maybe; - - tlsHandshakes: Maybe; - - inspect: Maybe; - }; - - export type UniqueSourcePrivateIpsHistogram = KpiNetworkChartFields.Fragment; - - export type UniqueDestinationPrivateIpsHistogram = KpiNetworkChartFields.Fragment; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetMatrixHistogramQuery { - export type Variables = { - defaultIndex: string[]; - filterQuery?: Maybe; - histogramType: HistogramType; - inspect: boolean; - sourceId: string; - stackByField: string; - timerange: TimerangeInput; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - MatrixHistogram: MatrixHistogram; - }; - - export type MatrixHistogram = { - __typename?: 'MatrixHistogramOverTimeData'; - - matrixHistogramData: MatrixHistogramData[]; - - totalCount: number; - - inspect: Maybe; - }; - - export type MatrixHistogramData = { - __typename?: 'MatrixOverTimeHistogramData'; - - x: Maybe; - - y: Maybe; - - g: Maybe; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetNetworkDnsQuery { - export type Variables = { - defaultIndex: string[]; - filterQuery?: Maybe; - inspect: boolean; - isPtrIncluded: boolean; - pagination: PaginationInputPaginated; - sort: NetworkDnsSortField; - sourceId: string; - stackByField?: Maybe; - timerange: TimerangeInput; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - NetworkDns: NetworkDns; - }; - - export type NetworkDns = { - __typename?: 'NetworkDnsData'; - - totalCount: number; - - edges: Edges[]; - - pageInfo: PageInfo; - - inspect: Maybe; - }; - - export type Edges = { - __typename?: 'NetworkDnsEdges'; - - node: Node; - - cursor: Cursor; - }; - - export type Node = { - __typename?: 'NetworkDnsItem'; - - _id: Maybe; - - dnsBytesIn: Maybe; - - dnsBytesOut: Maybe; - - dnsName: Maybe; - - queryCount: Maybe; - - uniqueDomains: Maybe; - }; - - export type Cursor = { - __typename?: 'CursorType'; - - value: Maybe; - }; - - export type PageInfo = { - __typename?: 'PageInfoPaginated'; - - activePage: number; - - fakeTotalCount: number; - - showMorePagesIndicator: boolean; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetNetworkHttpQuery { - export type Variables = { - sourceId: string; - ip?: Maybe; - filterQuery?: Maybe; - pagination: PaginationInputPaginated; - sort: NetworkHttpSortField; - timerange: TimerangeInput; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - NetworkHttp: NetworkHttp; - }; - - export type NetworkHttp = { - __typename?: 'NetworkHttpData'; - - totalCount: number; - - edges: Edges[]; - - pageInfo: PageInfo; - - inspect: Maybe; - }; - - export type Edges = { - __typename?: 'NetworkHttpEdges'; - - node: Node; - - cursor: Cursor; - }; - - export type Node = { - __typename?: 'NetworkHttpItem'; - - domains: string[]; - - lastHost: Maybe; - - lastSourceIp: Maybe; - - methods: string[]; - - path: Maybe; - - requestCount: Maybe; - - statuses: string[]; - }; - - export type Cursor = { - __typename?: 'CursorType'; - - value: Maybe; - }; - - export type PageInfo = { - __typename?: 'PageInfoPaginated'; - - activePage: number; - - fakeTotalCount: number; - - showMorePagesIndicator: boolean; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetNetworkTopCountriesQuery { - export type Variables = { - sourceId: string; - ip?: Maybe; - filterQuery?: Maybe; - pagination: PaginationInputPaginated; - sort: NetworkTopTablesSortField; - flowTarget: FlowTargetSourceDest; - timerange: TimerangeInput; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - NetworkTopCountries: NetworkTopCountries; - }; - - export type NetworkTopCountries = { - __typename?: 'NetworkTopCountriesData'; - - totalCount: number; - - edges: Edges[]; - - pageInfo: PageInfo; - - inspect: Maybe; - }; - - export type Edges = { - __typename?: 'NetworkTopCountriesEdges'; - - node: Node; - - cursor: Cursor; - }; - - export type Node = { - __typename?: 'NetworkTopCountriesItem'; - - source: Maybe<_Source>; - - destination: Maybe; - - network: Maybe; - }; - - export type _Source = { - __typename?: 'TopCountriesItemSource'; - - country: Maybe; - - destination_ips: Maybe; - - flows: Maybe; - - source_ips: Maybe; - }; - - export type Destination = { - __typename?: 'TopCountriesItemDestination'; - - country: Maybe; - - destination_ips: Maybe; - - flows: Maybe; - - source_ips: Maybe; - }; - - export type Network = { - __typename?: 'TopNetworkTablesEcsField'; - - bytes_in: Maybe; - - bytes_out: Maybe; - }; - - export type Cursor = { - __typename?: 'CursorType'; - - value: Maybe; - }; - - export type PageInfo = { - __typename?: 'PageInfoPaginated'; - - activePage: number; - - fakeTotalCount: number; - - showMorePagesIndicator: boolean; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetNetworkTopNFlowQuery { - export type Variables = { - sourceId: string; - ip?: Maybe; - filterQuery?: Maybe; - pagination: PaginationInputPaginated; - sort: NetworkTopTablesSortField; - flowTarget: FlowTargetSourceDest; - timerange: TimerangeInput; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - NetworkTopNFlow: NetworkTopNFlow; - }; - - export type NetworkTopNFlow = { - __typename?: 'NetworkTopNFlowData'; - - totalCount: number; - - edges: Edges[]; - - pageInfo: PageInfo; - - inspect: Maybe; - }; - - export type Edges = { - __typename?: 'NetworkTopNFlowEdges'; - - node: Node; - - cursor: Cursor; - }; - - export type Node = { - __typename?: 'NetworkTopNFlowItem'; - - source: Maybe<_Source>; - - destination: Maybe; - - network: Maybe; - }; - - export type _Source = { - __typename?: 'TopNFlowItemSource'; - - autonomous_system: Maybe; - - domain: Maybe; - - ip: Maybe; - - location: Maybe; - - flows: Maybe; - - destination_ips: Maybe; - }; - - export type AutonomousSystem = { - __typename?: 'AutonomousSystemItem'; - - name: Maybe; - - number: Maybe; - }; - - export type Location = { - __typename?: 'GeoItem'; - - geo: Maybe; - - flowTarget: Maybe; - }; - - export type Geo = { - __typename?: 'GeoEcsFields'; - - continent_name: Maybe; - - country_name: Maybe; - - country_iso_code: Maybe; - - city_name: Maybe; - - region_iso_code: Maybe; - - region_name: Maybe; - }; - - export type Destination = { - __typename?: 'TopNFlowItemDestination'; - - autonomous_system: Maybe<_AutonomousSystem>; - - domain: Maybe; - - ip: Maybe; - - location: Maybe<_Location>; - - flows: Maybe; - - source_ips: Maybe; - }; - - export type _AutonomousSystem = { - __typename?: 'AutonomousSystemItem'; - - name: Maybe; - - number: Maybe; - }; - - export type _Location = { - __typename?: 'GeoItem'; - - geo: Maybe<_Geo>; - - flowTarget: Maybe; - }; - - export type _Geo = { - __typename?: 'GeoEcsFields'; - - continent_name: Maybe; - - country_name: Maybe; - - country_iso_code: Maybe; - - city_name: Maybe; - - region_iso_code: Maybe; - - region_name: Maybe; - }; - - export type Network = { - __typename?: 'TopNetworkTablesEcsField'; - - bytes_in: Maybe; - - bytes_out: Maybe; - }; - - export type Cursor = { - __typename?: 'CursorType'; - - value: Maybe; - }; - - export type PageInfo = { - __typename?: 'PageInfoPaginated'; - - activePage: number; - - fakeTotalCount: number; - - showMorePagesIndicator: boolean; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetOverviewHostQuery { - export type Variables = { - sourceId: string; - timerange: TimerangeInput; - filterQuery?: Maybe; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - OverviewHost: Maybe; - }; - - export type OverviewHost = { - __typename?: 'OverviewHostData'; - - auditbeatAuditd: Maybe; - - auditbeatFIM: Maybe; - - auditbeatLogin: Maybe; - - auditbeatPackage: Maybe; - - auditbeatProcess: Maybe; - - auditbeatUser: Maybe; - - endgameDns: Maybe; - - endgameFile: Maybe; - - endgameImageLoad: Maybe; - - endgameNetwork: Maybe; - - endgameProcess: Maybe; - - endgameRegistry: Maybe; - - endgameSecurity: Maybe; - - filebeatSystemModule: Maybe; - - winlogbeatSecurity: Maybe; - - winlogbeatMWSysmonOperational: Maybe; - - inspect: Maybe; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetOverviewNetworkQuery { - export type Variables = { - sourceId: string; - timerange: TimerangeInput; - filterQuery?: Maybe; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - OverviewNetwork: Maybe; - }; - - export type OverviewNetwork = { - __typename?: 'OverviewNetworkData'; - - auditbeatSocket: Maybe; - - filebeatCisco: Maybe; - - filebeatNetflow: Maybe; - - filebeatPanw: Maybe; - - filebeatSuricata: Maybe; - - filebeatZeek: Maybe; - - packetbeatDNS: Maybe; - - packetbeatFlow: Maybe; - - packetbeatTLS: Maybe; - - inspect: Maybe; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace SourceQuery { - export type Variables = { - sourceId?: Maybe; - defaultIndex: string[]; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - status: Status; - }; - - export type Status = { - __typename?: 'SourceStatus'; - - indicesExist: boolean; - - indexFields: IndexFields[]; - }; - - export type IndexFields = { - __typename?: 'IndexField'; - - category: string; - - description: Maybe; - - example: Maybe; - - indexes: (Maybe)[]; - - name: string; - - searchable: boolean; - - type: string; - - aggregatable: boolean; - - format: Maybe; - }; -} - -export namespace GetAllTimeline { - export type Variables = { - pageInfo: PageInfoTimeline; - search?: Maybe; - sort?: Maybe; - onlyUserFavorite?: Maybe; - }; - - export type Query = { - __typename?: 'Query'; - - getAllTimeline: GetAllTimeline; - }; - - export type GetAllTimeline = { - __typename?: 'ResponseTimelines'; - - totalCount: Maybe; - - timeline: (Maybe)[]; - }; - - export type Timeline = { - __typename?: 'TimelineResult'; - - savedObjectId: string; - - description: Maybe; - - favorite: Maybe; - - eventIdToNoteIds: Maybe; - - notes: Maybe; - - noteIds: Maybe; - - pinnedEventIds: Maybe; - - title: Maybe; - - created: Maybe; - - createdBy: Maybe; - - updated: Maybe; - - updatedBy: Maybe; - - version: string; - }; - - export type Favorite = { - __typename?: 'FavoriteTimelineResult'; - - fullName: Maybe; - - userName: Maybe; - - favoriteDate: Maybe; - }; - - export type EventIdToNoteIds = { - __typename?: 'NoteResult'; - - eventId: Maybe; - - note: Maybe; - - timelineId: Maybe; - - noteId: string; - - created: Maybe; - - createdBy: Maybe; - - timelineVersion: Maybe; - - updated: Maybe; - - updatedBy: Maybe; - - version: Maybe; - }; - - export type Notes = { - __typename?: 'NoteResult'; - - eventId: Maybe; - - note: Maybe; - - timelineId: Maybe; - - timelineVersion: Maybe; - - noteId: string; - - created: Maybe; - - createdBy: Maybe; - - updated: Maybe; - - updatedBy: Maybe; - - version: Maybe; - }; -} - -export namespace DeleteTimelineMutation { - export type Variables = { - id: string[]; - }; - - export type Mutation = { - __typename?: 'Mutation'; - - deleteTimeline: boolean; - }; -} - -export namespace GetTimelineDetailsQuery { - export type Variables = { - sourceId: string; - eventId: string; - indexName: string; - defaultIndex: string[]; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - TimelineDetails: TimelineDetails; - }; - - export type TimelineDetails = { - __typename?: 'TimelineDetailsData'; - - data: Maybe; - }; - - export type Data = { - __typename?: 'DetailItem'; - - field: string; - - values: Maybe; - - originalValue: Maybe; - }; -} - -export namespace PersistTimelineFavoriteMutation { - export type Variables = { - timelineId?: Maybe; - }; - - export type Mutation = { - __typename?: 'Mutation'; - - persistFavorite: PersistFavorite; - }; - - export type PersistFavorite = { - __typename?: 'ResponseFavoriteTimeline'; - - savedObjectId: string; - - version: string; - - favorite: Maybe; - }; - - export type Favorite = { - __typename?: 'FavoriteTimelineResult'; - - fullName: Maybe; - - userName: Maybe; - - favoriteDate: Maybe; - }; -} - -export namespace GetTimelineQuery { - export type Variables = { - sourceId: string; - fieldRequested: string[]; - pagination: PaginationInput; - sortField: SortField; - filterQuery?: Maybe; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - Timeline: Timeline; - }; - - export type Timeline = { - __typename?: 'TimelineData'; - - totalCount: number; - - inspect: Maybe; - - pageInfo: PageInfo; - - edges: Edges[]; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; - - export type PageInfo = { - __typename?: 'PageInfo'; - - endCursor: Maybe; - - hasNextPage: Maybe; - }; - - export type EndCursor = { - __typename?: 'CursorType'; - - value: Maybe; - - tiebreaker: Maybe; - }; - - export type Edges = { - __typename?: 'TimelineEdges'; - - node: Node; - }; - - export type Node = { - __typename?: 'TimelineItem'; - - _id: string; - - _index: Maybe; - - data: Data[]; - - ecs: Ecs; - }; - - export type Data = { - __typename?: 'TimelineNonEcsData'; - - field: string; - - value: Maybe; - }; - - export type Ecs = { - __typename?: 'ECS'; - - _id: string; - - _index: Maybe; - - timestamp: Maybe; - - message: Maybe; - - system: Maybe; - - event: Maybe; - - auditd: Maybe; - - file: Maybe; - - host: Maybe; - - rule: Maybe; - - source: Maybe<_Source>; - - destination: Maybe; - - dns: Maybe; - - endgame: Maybe; - - geo: Maybe<__Geo>; - - signal: Maybe; - - suricata: Maybe; - - network: Maybe; - - http: Maybe; - - tls: Maybe; - - url: Maybe; - - user: Maybe; - - winlog: Maybe; - - process: Maybe; - - zeek: Maybe; - }; - - export type System = { - __typename?: 'SystemEcsField'; - - auth: Maybe; - - audit: Maybe; - }; - - export type Auth = { - __typename?: 'AuthEcsFields'; - - ssh: Maybe; - }; - - export type Ssh = { - __typename?: 'SshEcsFields'; - - signature: Maybe; - - method: Maybe; - }; - - export type Audit = { - __typename?: 'AuditEcsFields'; - - package: Maybe; - }; - - export type Package = { - __typename?: 'PackageEcsFields'; - - arch: Maybe; - - entity_id: Maybe; - - name: Maybe; - - size: Maybe; - - summary: Maybe; - - version: Maybe; - }; - - export type Event = { - __typename?: 'EventEcsFields'; - - action: Maybe; - - category: Maybe; - - code: Maybe; - - created: Maybe; - - dataset: Maybe; - - duration: Maybe; - - end: Maybe; - - hash: Maybe; - - id: Maybe; - - kind: Maybe; - - module: Maybe; - - original: Maybe; - - outcome: Maybe; - - risk_score: Maybe; - - risk_score_norm: Maybe; - - severity: Maybe; - - start: Maybe; - - timezone: Maybe; - - type: Maybe; - }; - - export type Auditd = { - __typename?: 'AuditdEcsFields'; - - result: Maybe; - - session: Maybe; - - data: Maybe<_Data>; - - summary: Maybe; - }; - - export type _Data = { - __typename?: 'AuditdData'; - - acct: Maybe; - - terminal: Maybe; - - op: Maybe; - }; - - export type Summary = { - __typename?: 'Summary'; - - actor: Maybe; - - object: Maybe; - - how: Maybe; - - message_type: Maybe; - - sequence: Maybe; - }; - - export type Actor = { - __typename?: 'PrimarySecondary'; - - primary: Maybe; - - secondary: Maybe; - }; - - export type Object = { - __typename?: 'PrimarySecondary'; - - primary: Maybe; - - secondary: Maybe; - - type: Maybe; - }; - - export type File = { - __typename?: 'FileFields'; - - name: Maybe; - - path: Maybe; - - target_path: Maybe; - - extension: Maybe; - - type: Maybe; - - device: Maybe; - - inode: Maybe; - - uid: Maybe; - - owner: Maybe; - - gid: Maybe; - - group: Maybe; - - mode: Maybe; - - size: Maybe; - - mtime: Maybe; - - ctime: Maybe; - }; - - export type Host = { - __typename?: 'HostEcsFields'; - - id: Maybe; - - name: Maybe; - - ip: Maybe; - }; - - export type Rule = { - __typename?: 'RuleEcsField'; - - reference: Maybe; - }; - - export type _Source = { - __typename?: 'SourceEcsFields'; - - bytes: Maybe; - - ip: Maybe; - - packets: Maybe; - - port: Maybe; - - geo: Maybe; - }; - - export type Geo = { - __typename?: 'GeoEcsFields'; - - continent_name: Maybe; - - country_name: Maybe; - - country_iso_code: Maybe; - - city_name: Maybe; - - region_iso_code: Maybe; - - region_name: Maybe; - }; - - export type Destination = { - __typename?: 'DestinationEcsFields'; - - bytes: Maybe; - - ip: Maybe; - - packets: Maybe; - - port: Maybe; - - geo: Maybe<_Geo>; - }; - - export type _Geo = { - __typename?: 'GeoEcsFields'; - - continent_name: Maybe; - - country_name: Maybe; - - country_iso_code: Maybe; - - city_name: Maybe; - - region_iso_code: Maybe; - - region_name: Maybe; - }; - - export type Dns = { - __typename?: 'DnsEcsFields'; - - question: Maybe; - - resolved_ip: Maybe; - - response_code: Maybe; - }; - - export type Question = { - __typename?: 'DnsQuestionData'; - - name: Maybe; - - type: Maybe; - }; - - export type Endgame = { - __typename?: 'EndgameEcsFields'; - - exit_code: Maybe; - - file_name: Maybe; - - file_path: Maybe; - - logon_type: Maybe; - - parent_process_name: Maybe; - - pid: Maybe; - - process_name: Maybe; - - subject_domain_name: Maybe; - - subject_logon_id: Maybe; - - subject_user_name: Maybe; - - target_domain_name: Maybe; - - target_logon_id: Maybe; - - target_user_name: Maybe; - }; - - export type __Geo = { - __typename?: 'GeoEcsFields'; - - region_name: Maybe; - - country_iso_code: Maybe; - }; - - export type Signal = { - __typename?: 'SignalField'; - - original_time: Maybe; - - rule: Maybe<_Rule>; - }; - - export type _Rule = { - __typename?: 'RuleField'; - - id: Maybe; - - saved_id: Maybe; - - timeline_id: Maybe; - - timeline_title: Maybe; - - output_index: Maybe; - - from: Maybe; - - index: Maybe; - - language: Maybe; - - query: Maybe; - - to: Maybe; - - filters: Maybe; - }; - - export type Suricata = { - __typename?: 'SuricataEcsFields'; - - eve: Maybe; - }; - - export type Eve = { - __typename?: 'SuricataEveData'; - - proto: Maybe; - - flow_id: Maybe; - - alert: Maybe; - }; - - export type Alert = { - __typename?: 'SuricataAlertData'; - - signature: Maybe; - - signature_id: Maybe; - }; - - export type Network = { - __typename?: 'NetworkEcsField'; - - bytes: Maybe; - - community_id: Maybe; - - direction: Maybe; - - packets: Maybe; - - protocol: Maybe; - - transport: Maybe; - }; - - export type Http = { - __typename?: 'HttpEcsFields'; - - version: Maybe; - - request: Maybe; - - response: Maybe; - }; - - export type Request = { - __typename?: 'HttpRequestData'; - - method: Maybe; - - body: Maybe; - - referrer: Maybe; - }; - - export type Body = { - __typename?: 'HttpBodyData'; - - bytes: Maybe; - - content: Maybe; - }; - - export type Response = { - __typename?: 'HttpResponseData'; - - status_code: Maybe; - - body: Maybe<_Body>; - }; - - export type _Body = { - __typename?: 'HttpBodyData'; - - bytes: Maybe; - - content: Maybe; - }; - - export type Tls = { - __typename?: 'TlsEcsFields'; - - client_certificate: Maybe; - - fingerprints: Maybe; - - server_certificate: Maybe; - }; - - export type ClientCertificate = { - __typename?: 'TlsClientCertificateData'; - - fingerprint: Maybe; - }; - - export type Fingerprint = { - __typename?: 'FingerprintData'; - - sha1: Maybe; - }; - - export type Fingerprints = { - __typename?: 'TlsFingerprintsData'; - - ja3: Maybe; - }; - - export type Ja3 = { - __typename?: 'TlsJa3Data'; - - hash: Maybe; - }; - - export type ServerCertificate = { - __typename?: 'TlsServerCertificateData'; - - fingerprint: Maybe<_Fingerprint>; - }; - - export type _Fingerprint = { - __typename?: 'FingerprintData'; - - sha1: Maybe; - }; - - export type Url = { - __typename?: 'UrlEcsFields'; - - original: Maybe; - - domain: Maybe; - - username: Maybe; - - password: Maybe; - }; - - export type User = { - __typename?: 'UserEcsFields'; - - domain: Maybe; - - name: Maybe; - }; - - export type Winlog = { - __typename?: 'WinlogEcsFields'; - - event_id: Maybe; - }; - - export type Process = { - __typename?: 'ProcessEcsFields'; - - hash: Maybe; - - pid: Maybe; - - name: Maybe; - - ppid: Maybe; - - args: Maybe; - - executable: Maybe; - - title: Maybe; - - working_directory: Maybe; - }; - - export type Hash = { - __typename?: 'ProcessHashData'; - - md5: Maybe; - - sha1: Maybe; - - sha256: Maybe; - }; - - export type Zeek = { - __typename?: 'ZeekEcsFields'; - - session_id: Maybe; - - connection: Maybe; - - notice: Maybe; - - dns: Maybe<_Dns>; - - http: Maybe<_Http>; - - files: Maybe; - - ssl: Maybe; - }; - - export type Connection = { - __typename?: 'ZeekConnectionData'; - - local_resp: Maybe; - - local_orig: Maybe; - - missed_bytes: Maybe; - - state: Maybe; - - history: Maybe; - }; - - export type Notice = { - __typename?: 'ZeekNoticeData'; - - suppress_for: Maybe; - - msg: Maybe; - - note: Maybe; - - sub: Maybe; - - dst: Maybe; - - dropped: Maybe; - - peer_descr: Maybe; - }; - - export type _Dns = { - __typename?: 'ZeekDnsData'; - - AA: Maybe; - - qclass_name: Maybe; - - RD: Maybe; - - qtype_name: Maybe; - - rejected: Maybe; - - qtype: Maybe; - - query: Maybe; - - trans_id: Maybe; - - qclass: Maybe; - - RA: Maybe; - - TC: Maybe; - }; - - export type _Http = { - __typename?: 'ZeekHttpData'; - - resp_mime_types: Maybe; - - trans_depth: Maybe; - - status_msg: Maybe; - - resp_fuids: Maybe; - - tags: Maybe; - }; - - export type Files = { - __typename?: 'ZeekFileData'; - - session_ids: Maybe; - - timedout: Maybe; - - local_orig: Maybe; - - tx_host: Maybe; - - source: Maybe; - - is_orig: Maybe; - - overflow_bytes: Maybe; - - sha1: Maybe; - - duration: Maybe; - - depth: Maybe; - - analyzers: Maybe; - - mime_type: Maybe; - - rx_host: Maybe; - - total_bytes: Maybe; - - fuid: Maybe; - - seen_bytes: Maybe; - - missing_bytes: Maybe; - - md5: Maybe; - }; - - export type Ssl = { - __typename?: 'ZeekSslData'; - - cipher: Maybe; - - established: Maybe; - - resumed: Maybe; - - version: Maybe; - }; -} - -export namespace PersistTimelineNoteMutation { - export type Variables = { - noteId?: Maybe; - version?: Maybe; - note: NoteInput; - }; - - export type Mutation = { - __typename?: 'Mutation'; - - persistNote: PersistNote; - }; - - export type PersistNote = { - __typename?: 'ResponseNote'; - - code: Maybe; - - message: Maybe; - - note: Note; - }; - - export type Note = { - __typename?: 'NoteResult'; - - eventId: Maybe; - - note: Maybe; - - timelineId: Maybe; - - timelineVersion: Maybe; - - noteId: string; - - created: Maybe; - - createdBy: Maybe; - - updated: Maybe; - - updatedBy: Maybe; - - version: Maybe; - }; -} - -export namespace GetOneTimeline { - export type Variables = { - id: string; - }; - - export type Query = { - __typename?: 'Query'; - - getOneTimeline: GetOneTimeline; - }; - - export type GetOneTimeline = { - __typename?: 'TimelineResult'; - - savedObjectId: string; - - columns: Maybe; - - dataProviders: Maybe; - - dateRange: Maybe; - - description: Maybe; - - eventType: Maybe; - - eventIdToNoteIds: Maybe; - - favorite: Maybe; - - filters: Maybe; - - kqlMode: Maybe; - - kqlQuery: Maybe; - - notes: Maybe; - - noteIds: Maybe; - - pinnedEventIds: Maybe; - - pinnedEventsSaveObject: Maybe; - - title: Maybe; - - savedQueryId: Maybe; - - sort: Maybe; - - created: Maybe; - - createdBy: Maybe; - - updated: Maybe; - - updatedBy: Maybe; - - version: string; - }; - - export type Columns = { - __typename?: 'ColumnHeaderResult'; - - aggregatable: Maybe; - - category: Maybe; - - columnHeaderType: Maybe; - - description: Maybe; - - example: Maybe; - - indexes: Maybe; - - id: Maybe; - - name: Maybe; - - searchable: Maybe; - - type: Maybe; - }; - - export type DataProviders = { - __typename?: 'DataProviderResult'; - - id: Maybe; - - name: Maybe; - - enabled: Maybe; - - excluded: Maybe; - - kqlQuery: Maybe; - - queryMatch: Maybe; - - and: Maybe; - }; - - export type QueryMatch = { - __typename?: 'QueryMatchResult'; - - field: Maybe; - - displayField: Maybe; - - value: Maybe; - - displayValue: Maybe; - - operator: Maybe; - }; - - export type And = { - __typename?: 'DataProviderResult'; - - id: Maybe; - - name: Maybe; - - enabled: Maybe; - - excluded: Maybe; - - kqlQuery: Maybe; - - queryMatch: Maybe<_QueryMatch>; - }; - - export type _QueryMatch = { - __typename?: 'QueryMatchResult'; - - field: Maybe; - - displayField: Maybe; - - value: Maybe; - - displayValue: Maybe; - - operator: Maybe; - }; - - export type DateRange = { - __typename?: 'DateRangePickerResult'; - - start: Maybe; - - end: Maybe; - }; - - export type EventIdToNoteIds = { - __typename?: 'NoteResult'; - - eventId: Maybe; - - note: Maybe; - - timelineId: Maybe; - - noteId: string; - - created: Maybe; - - createdBy: Maybe; - - timelineVersion: Maybe; - - updated: Maybe; - - updatedBy: Maybe; - - version: Maybe; - }; - - export type Favorite = { - __typename?: 'FavoriteTimelineResult'; - - fullName: Maybe; - - userName: Maybe; - - favoriteDate: Maybe; - }; - - export type Filters = { - __typename?: 'FilterTimelineResult'; - - meta: Maybe; - - query: Maybe; - - exists: Maybe; - - match_all: Maybe; - - missing: Maybe; - - range: Maybe; - - script: Maybe; - }; - - export type Meta = { - __typename?: 'FilterMetaTimelineResult'; - - alias: Maybe; - - controlledBy: Maybe; - - disabled: Maybe; - - field: Maybe; - - formattedValue: Maybe; - - index: Maybe; - - key: Maybe; - - negate: Maybe; - - params: Maybe; - - type: Maybe; - - value: Maybe; - }; - - export type KqlQuery = { - __typename?: 'SerializedFilterQueryResult'; - - filterQuery: Maybe; - }; - - export type FilterQuery = { - __typename?: 'SerializedKueryQueryResult'; - - kuery: Maybe; - - serializedQuery: Maybe; - }; - - export type Kuery = { - __typename?: 'KueryFilterQueryResult'; - - kind: Maybe; - - expression: Maybe; - }; - - export type Notes = { - __typename?: 'NoteResult'; - - eventId: Maybe; - - note: Maybe; - - timelineId: Maybe; - - timelineVersion: Maybe; - - noteId: string; - - created: Maybe; - - createdBy: Maybe; - - updated: Maybe; - - updatedBy: Maybe; - - version: Maybe; - }; - - export type PinnedEventsSaveObject = { - __typename?: 'PinnedEvent'; - - pinnedEventId: string; - - eventId: Maybe; - - timelineId: Maybe; - - created: Maybe; - - createdBy: Maybe; - - updated: Maybe; - - updatedBy: Maybe; - - version: Maybe; - }; - - export type Sort = { - __typename?: 'SortTimelineResult'; - - columnId: Maybe; - - sortDirection: Maybe; - }; -} - -export namespace PersistTimelineMutation { - export type Variables = { - timelineId?: Maybe; - version?: Maybe; - timeline: TimelineInput; - }; - - export type Mutation = { - __typename?: 'Mutation'; - - persistTimeline: PersistTimeline; - }; - - export type PersistTimeline = { - __typename?: 'ResponseTimeline'; - - code: Maybe; - - message: Maybe; - - timeline: Timeline; - }; - - export type Timeline = { - __typename?: 'TimelineResult'; - - savedObjectId: string; - - version: string; - - columns: Maybe; - - dataProviders: Maybe; - - description: Maybe; - - eventType: Maybe; - - favorite: Maybe; - - filters: Maybe; - - kqlMode: Maybe; - - kqlQuery: Maybe; - - title: Maybe; - - dateRange: Maybe; - - savedQueryId: Maybe; - - sort: Maybe; - - created: Maybe; - - createdBy: Maybe; - - updated: Maybe; - - updatedBy: Maybe; - }; - - export type Columns = { - __typename?: 'ColumnHeaderResult'; - - aggregatable: Maybe; - - category: Maybe; - - columnHeaderType: Maybe; - - description: Maybe; - - example: Maybe; - - indexes: Maybe; - - id: Maybe; - - name: Maybe; - - searchable: Maybe; - - type: Maybe; - }; - - export type DataProviders = { - __typename?: 'DataProviderResult'; - - id: Maybe; - - name: Maybe; - - enabled: Maybe; - - excluded: Maybe; - - kqlQuery: Maybe; - - queryMatch: Maybe; - - and: Maybe; - }; - - export type QueryMatch = { - __typename?: 'QueryMatchResult'; - - field: Maybe; - - displayField: Maybe; - - value: Maybe; - - displayValue: Maybe; - - operator: Maybe; - }; - - export type And = { - __typename?: 'DataProviderResult'; - - id: Maybe; - - name: Maybe; - - enabled: Maybe; - - excluded: Maybe; - - kqlQuery: Maybe; - - queryMatch: Maybe<_QueryMatch>; - }; - - export type _QueryMatch = { - __typename?: 'QueryMatchResult'; - - field: Maybe; - - displayField: Maybe; - - value: Maybe; - - displayValue: Maybe; - - operator: Maybe; - }; - - export type Favorite = { - __typename?: 'FavoriteTimelineResult'; - - fullName: Maybe; - - userName: Maybe; - - favoriteDate: Maybe; - }; - - export type Filters = { - __typename?: 'FilterTimelineResult'; - - meta: Maybe; - - query: Maybe; - - exists: Maybe; - - match_all: Maybe; - - missing: Maybe; - - range: Maybe; - - script: Maybe; - }; - - export type Meta = { - __typename?: 'FilterMetaTimelineResult'; - - alias: Maybe; - - controlledBy: Maybe; - - disabled: Maybe; - - field: Maybe; - - formattedValue: Maybe; - - index: Maybe; - - key: Maybe; - - negate: Maybe; - - params: Maybe; - - type: Maybe; - - value: Maybe; - }; - - export type KqlQuery = { - __typename?: 'SerializedFilterQueryResult'; - - filterQuery: Maybe; - }; - - export type FilterQuery = { - __typename?: 'SerializedKueryQueryResult'; - - kuery: Maybe; - - serializedQuery: Maybe; - }; - - export type Kuery = { - __typename?: 'KueryFilterQueryResult'; - - kind: Maybe; - - expression: Maybe; - }; - - export type DateRange = { - __typename?: 'DateRangePickerResult'; - - start: Maybe; - - end: Maybe; - }; - - export type Sort = { - __typename?: 'SortTimelineResult'; - - columnId: Maybe; - - sortDirection: Maybe; - }; -} - -export namespace PersistTimelinePinnedEventMutation { - export type Variables = { - pinnedEventId?: Maybe; - eventId: string; - timelineId?: Maybe; - }; - - export type Mutation = { - __typename?: 'Mutation'; - - persistPinnedEventOnTimeline: Maybe; - }; - - export type PersistPinnedEventOnTimeline = { - __typename?: 'PinnedEvent'; - - pinnedEventId: string; - - eventId: Maybe; - - timelineId: Maybe; - - timelineVersion: Maybe; - - created: Maybe; - - createdBy: Maybe; - - updated: Maybe; - - updatedBy: Maybe; - - version: Maybe; - }; -} - -export namespace GetTlsQuery { - export type Variables = { - sourceId: string; - filterQuery?: Maybe; - flowTarget: FlowTargetSourceDest; - ip: string; - pagination: PaginationInputPaginated; - sort: TlsSortField; - timerange: TimerangeInput; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - Tls: Tls; - }; - - export type Tls = { - __typename?: 'TlsData'; - - totalCount: number; - - edges: Edges[]; - - pageInfo: PageInfo; - - inspect: Maybe; - }; - - export type Edges = { - __typename?: 'TlsEdges'; - - node: Node; - - cursor: Cursor; - }; - - export type Node = { - __typename?: 'TlsNode'; - - _id: Maybe; - - alternativeNames: Maybe; - - commonNames: Maybe; - - ja3: Maybe; - - issuerNames: Maybe; - - notAfter: Maybe; - }; - - export type Cursor = { - __typename?: 'CursorType'; - - value: Maybe; - }; - - export type PageInfo = { - __typename?: 'PageInfoPaginated'; - - activePage: number; - - fakeTotalCount: number; - - showMorePagesIndicator: boolean; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetUncommonProcessesQuery { - export type Variables = { - sourceId: string; - timerange: TimerangeInput; - pagination: PaginationInputPaginated; - filterQuery?: Maybe; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - UncommonProcesses: UncommonProcesses; - }; - - export type UncommonProcesses = { - __typename?: 'UncommonProcessesData'; - - totalCount: number; - - edges: Edges[]; - - pageInfo: PageInfo; - - inspect: Maybe; - }; - - export type Edges = { - __typename?: 'UncommonProcessesEdges'; - - node: Node; - - cursor: Cursor; - }; - - export type Node = { - __typename?: 'UncommonProcessItem'; - - _id: string; - - instances: number; - - process: Process; - - user: Maybe; - - hosts: Hosts[]; - }; - - export type Process = { - __typename?: 'ProcessEcsFields'; - - args: Maybe; - - name: Maybe; - }; - - export type User = { - __typename?: 'UserEcsFields'; - - id: Maybe; - - name: Maybe; - }; - - export type Hosts = { - __typename?: 'HostEcsFields'; - - name: Maybe; - }; - - export type Cursor = { - __typename?: 'CursorType'; - - value: Maybe; - }; - - export type PageInfo = { - __typename?: 'PageInfoPaginated'; - - activePage: number; - - fakeTotalCount: number; - - showMorePagesIndicator: boolean; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace GetUsersQuery { - export type Variables = { - sourceId: string; - filterQuery?: Maybe; - flowTarget: FlowTarget; - ip: string; - pagination: PaginationInputPaginated; - sort: UsersSortField; - timerange: TimerangeInput; - defaultIndex: string[]; - inspect: boolean; - }; - - export type Query = { - __typename?: 'Query'; - - source: Source; - }; - - export type Source = { - __typename?: 'Source'; - - id: string; - - Users: Users; - }; - - export type Users = { - __typename?: 'UsersData'; - - totalCount: number; - - edges: Edges[]; - - pageInfo: PageInfo; - - inspect: Maybe; - }; - - export type Edges = { - __typename?: 'UsersEdges'; - - node: Node; - - cursor: Cursor; - }; - - export type Node = { - __typename?: 'UsersNode'; - - user: Maybe; - }; - - export type User = { - __typename?: 'UsersItem'; - - name: Maybe; - - id: Maybe; - - groupId: Maybe; - - groupName: Maybe; - - count: Maybe; - }; - - export type Cursor = { - __typename?: 'CursorType'; - - value: Maybe; - }; - - export type PageInfo = { - __typename?: 'PageInfoPaginated'; - - activePage: number; - - fakeTotalCount: number; - - showMorePagesIndicator: boolean; - }; - - export type Inspect = { - __typename?: 'Inspect'; - - dsl: string[]; - - response: string[]; - }; -} - -export namespace KpiHostDetailsChartFields { - export type Fragment = { - __typename?: 'KpiHostHistogramData'; - - x: Maybe; - - y: Maybe; - }; -} - -export namespace KpiHostChartFields { - export type Fragment = { - __typename?: 'KpiHostHistogramData'; - - x: Maybe; - - y: Maybe; - }; -} - -export namespace KpiNetworkChartFields { - export type Fragment = { - __typename?: 'KpiNetworkHistogramData'; - - x: Maybe; - - y: Maybe; - }; -} diff --git a/x-pack/legacy/plugins/siem/public/graphql/types.tsx b/x-pack/legacy/plugins/siem/public/graphql/types.tsx new file mode 100644 index 0000000000000..6bf0e89ff5b8d --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/graphql/types.tsx @@ -0,0 +1,5314 @@ +/* + * 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. + */ + +/* tslint:disable */ +/* eslint-disable */ + +import gql from 'graphql-tag'; +import * as React from 'react'; +import * as ApolloReactCommon from '@apollo/client'; +import * as ApolloReactComponents from '@apollo/react-components'; +import * as ApolloReactHooks from '@apollo/client'; +export type Maybe = T | null; +export type Omit = Pick>; + +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: string, + String: string, + Boolean: boolean, + Int: number, + Float: number, + ToStringArray: string[], + Date: string, + ToNumberArray: number[], + ToDateArray: string[], + ToBooleanArray: boolean[], + ToAny: any, + EsValue: any, +}; + +export type AuditdData = { + __typename?: 'AuditdData', + acct?: Maybe, + terminal?: Maybe, + op?: Maybe, +}; + +export type AuditdEcsFields = { + __typename?: 'AuditdEcsFields', + result?: Maybe, + session?: Maybe, + data?: Maybe, + summary?: Maybe, + sequence?: Maybe, +}; + +export type AuditEcsFields = { + __typename?: 'AuditEcsFields', + package?: Maybe, +}; + +export type AuthEcsFields = { + __typename?: 'AuthEcsFields', + ssh?: Maybe, +}; + +export type AuthenticationItem = { + __typename?: 'AuthenticationItem', + _id: Scalars['String'], + failures: Scalars['Float'], + successes: Scalars['Float'], + user: UserEcsFields, + lastSuccess?: Maybe, + lastFailure?: Maybe, +}; + +export type AuthenticationsData = { + __typename?: 'AuthenticationsData', + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +}; + +export type AuthenticationsEdges = { + __typename?: 'AuthenticationsEdges', + node: AuthenticationItem, + cursor: CursorType, +}; + +export type AutonomousSystem = { + __typename?: 'AutonomousSystem', + number?: Maybe, + organization?: Maybe, +}; + +export type AutonomousSystemItem = { + __typename?: 'AutonomousSystemItem', + name?: Maybe, + number?: Maybe, +}; + +export type AutonomousSystemOrganization = { + __typename?: 'AutonomousSystemOrganization', + name?: Maybe, +}; + +export type CloudFields = { + __typename?: 'CloudFields', + instance?: Maybe, + machine?: Maybe, + provider?: Maybe>>, + region?: Maybe>>, +}; + +export type CloudInstance = { + __typename?: 'CloudInstance', + id?: Maybe>>, +}; + +export type CloudMachine = { + __typename?: 'CloudMachine', + type?: Maybe>>, +}; + +export type ColumnHeaderInput = { + aggregatable?: Maybe, + category?: Maybe, + columnHeaderType?: Maybe, + description?: Maybe, + example?: Maybe, + indexes?: Maybe>, + id?: Maybe, + name?: Maybe, + placeholder?: Maybe, + searchable?: Maybe, + type?: Maybe, +}; + +export type ColumnHeaderResult = { + __typename?: 'ColumnHeaderResult', + aggregatable?: Maybe, + category?: Maybe, + columnHeaderType?: Maybe, + description?: Maybe, + example?: Maybe, + indexes?: Maybe>, + id?: Maybe, + name?: Maybe, + placeholder?: Maybe, + searchable?: Maybe, + type?: Maybe, +}; + +export type CursorType = { + __typename?: 'CursorType', + value?: Maybe, + tiebreaker?: Maybe, +}; + +export type DataProviderInput = { + id?: Maybe, + name?: Maybe, + enabled?: Maybe, + excluded?: Maybe, + kqlQuery?: Maybe, + queryMatch?: Maybe, + and?: Maybe>, +}; + +export type DataProviderResult = { + __typename?: 'DataProviderResult', + id?: Maybe, + name?: Maybe, + enabled?: Maybe, + excluded?: Maybe, + kqlQuery?: Maybe, + queryMatch?: Maybe, + and?: Maybe>, +}; + + +export type DateRangePickerInput = { + start?: Maybe, + end?: Maybe, +}; + +export type DateRangePickerResult = { + __typename?: 'DateRangePickerResult', + start?: Maybe, + end?: Maybe, +}; + +export type DestinationEcsFields = { + __typename?: 'DestinationEcsFields', + bytes?: Maybe, + ip?: Maybe, + port?: Maybe, + domain?: Maybe, + geo?: Maybe, + packets?: Maybe, +}; + +export type DetailItem = { + __typename?: 'DetailItem', + field: Scalars['String'], + values?: Maybe, + originalValue?: Maybe, +}; + +export enum Direction { + asc = 'asc', + desc = 'desc' +} + +export type DnsEcsFields = { + __typename?: 'DnsEcsFields', + question?: Maybe, + resolved_ip?: Maybe, + response_code?: Maybe, +}; + +export type DnsQuestionData = { + __typename?: 'DnsQuestionData', + name?: Maybe, + type?: Maybe, +}; + +export type Ecs = { + __typename?: 'ECS', + _id: Scalars['String'], + _index?: Maybe, + auditd?: Maybe, + destination?: Maybe, + dns?: Maybe, + endgame?: Maybe, + event?: Maybe, + geo?: Maybe, + host?: Maybe, + network?: Maybe, + rule?: Maybe, + signal?: Maybe, + source?: Maybe, + suricata?: Maybe, + tls?: Maybe, + zeek?: Maybe, + http?: Maybe, + url?: Maybe, + timestamp?: Maybe, + message?: Maybe, + user?: Maybe, + winlog?: Maybe, + process?: Maybe, + file?: Maybe, + system?: Maybe, +}; + +export type EcsEdges = { + __typename?: 'EcsEdges', + node: Ecs, + cursor: CursorType, +}; + +export type EndgameEcsFields = { + __typename?: 'EndgameEcsFields', + exit_code?: Maybe, + file_name?: Maybe, + file_path?: Maybe, + logon_type?: Maybe, + parent_process_name?: Maybe, + pid?: Maybe, + process_name?: Maybe, + subject_domain_name?: Maybe, + subject_logon_id?: Maybe, + subject_user_name?: Maybe, + target_domain_name?: Maybe, + target_logon_id?: Maybe, + target_user_name?: Maybe, +}; + + +export type EventEcsFields = { + __typename?: 'EventEcsFields', + action?: Maybe, + category?: Maybe, + code?: Maybe, + created?: Maybe, + dataset?: Maybe, + duration?: Maybe, + end?: Maybe, + hash?: Maybe, + id?: Maybe, + kind?: Maybe, + module?: Maybe, + original?: Maybe, + outcome?: Maybe, + risk_score?: Maybe, + risk_score_norm?: Maybe, + severity?: Maybe, + start?: Maybe, + timezone?: Maybe, + type?: Maybe, +}; + +export type EventsTimelineData = { + __typename?: 'EventsTimelineData', + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfo, + inspect?: Maybe, +}; + +export type FavoriteTimelineInput = { + fullName?: Maybe, + userName?: Maybe, + favoriteDate?: Maybe, +}; + +export type FavoriteTimelineResult = { + __typename?: 'FavoriteTimelineResult', + fullName?: Maybe, + userName?: Maybe, + favoriteDate?: Maybe, +}; + +export type FileFields = { + __typename?: 'FileFields', + name?: Maybe, + path?: Maybe, + target_path?: Maybe, + extension?: Maybe, + type?: Maybe, + device?: Maybe, + inode?: Maybe, + uid?: Maybe, + owner?: Maybe, + gid?: Maybe, + group?: Maybe, + mode?: Maybe, + size?: Maybe, + mtime?: Maybe, + ctime?: Maybe, +}; + +export type FilterMetaTimelineInput = { + alias?: Maybe, + controlledBy?: Maybe, + disabled?: Maybe, + field?: Maybe, + formattedValue?: Maybe, + index?: Maybe, + key?: Maybe, + negate?: Maybe, + params?: Maybe, + type?: Maybe, + value?: Maybe, +}; + +export type FilterMetaTimelineResult = { + __typename?: 'FilterMetaTimelineResult', + alias?: Maybe, + controlledBy?: Maybe, + disabled?: Maybe, + field?: Maybe, + formattedValue?: Maybe, + index?: Maybe, + key?: Maybe, + negate?: Maybe, + params?: Maybe, + type?: Maybe, + value?: Maybe, +}; + +export type FilterTimelineInput = { + exists?: Maybe, + meta?: Maybe, + match_all?: Maybe, + missing?: Maybe, + query?: Maybe, + range?: Maybe, + script?: Maybe, +}; + +export type FilterTimelineResult = { + __typename?: 'FilterTimelineResult', + exists?: Maybe, + meta?: Maybe, + match_all?: Maybe, + missing?: Maybe, + query?: Maybe, + range?: Maybe, + script?: Maybe, +}; + +export type FingerprintData = { + __typename?: 'FingerprintData', + sha1?: Maybe, +}; + +export type FirstLastSeenHost = { + __typename?: 'FirstLastSeenHost', + inspect?: Maybe, + firstSeen?: Maybe, + lastSeen?: Maybe, +}; + +export enum FlowDirection { + uniDirectional = 'uniDirectional', + biDirectional = 'biDirectional' +} + +export enum FlowTarget { + client = 'client', + destination = 'destination', + server = 'server', + source = 'source' +} + +export enum FlowTargetSourceDest { + destination = 'destination', + source = 'source' +} + +export type GeoEcsFields = { + __typename?: 'GeoEcsFields', + city_name?: Maybe, + continent_name?: Maybe, + country_iso_code?: Maybe, + country_name?: Maybe, + location?: Maybe, + region_iso_code?: Maybe, + region_name?: Maybe, +}; + +export type GeoItem = { + __typename?: 'GeoItem', + geo?: Maybe, + flowTarget?: Maybe, +}; + +export enum HistogramType { + authentications = 'authentications', + anomalies = 'anomalies', + events = 'events', + alerts = 'alerts', + dns = 'dns' +} + +export type HostEcsFields = { + __typename?: 'HostEcsFields', + architecture?: Maybe, + id?: Maybe, + ip?: Maybe, + mac?: Maybe, + name?: Maybe, + os?: Maybe, + type?: Maybe, +}; + +export type HostFields = { + __typename?: 'HostFields', + architecture?: Maybe, + id?: Maybe, + ip?: Maybe>>, + mac?: Maybe>>, + name?: Maybe, + os?: Maybe, + type?: Maybe, +}; + +export type HostItem = { + __typename?: 'HostItem', + _id?: Maybe, + lastSeen?: Maybe, + host?: Maybe, + cloud?: Maybe, + inspect?: Maybe, +}; + +export type HostsData = { + __typename?: 'HostsData', + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +}; + +export type HostsEdges = { + __typename?: 'HostsEdges', + node: HostItem, + cursor: CursorType, +}; + +export enum HostsFields { + hostName = 'hostName', + lastSeen = 'lastSeen' +} + +export type HostsSortField = { + field: HostsFields, + direction: Direction, +}; + +export type HttpBodyData = { + __typename?: 'HttpBodyData', + content?: Maybe, + bytes?: Maybe, +}; + +export type HttpEcsFields = { + __typename?: 'HttpEcsFields', + version?: Maybe, + request?: Maybe, + response?: Maybe, +}; + +export type HttpRequestData = { + __typename?: 'HttpRequestData', + method?: Maybe, + body?: Maybe, + referrer?: Maybe, + bytes?: Maybe, +}; + +export type HttpResponseData = { + __typename?: 'HttpResponseData', + status_code?: Maybe, + body?: Maybe, + bytes?: Maybe, +}; + +/** A descriptor of a field in an index */ +export type IndexField = { + __typename?: 'IndexField', + /** Where the field belong */ + category: Scalars['String'], + /** Example of field's value */ + example?: Maybe, + /** whether the field's belong to an alias index */ + indexes: Array>, + /** The name of the field */ + name: Scalars['String'], + /** The type of the field's values as recognized by Kibana */ + type: Scalars['String'], + /** Whether the field's values can be efficiently searched for */ + searchable: Scalars['Boolean'], + /** Whether the field's values can be aggregated */ + aggregatable: Scalars['Boolean'], + /** Description of the field */ + description?: Maybe, + format?: Maybe, +}; + +export type Inspect = { + __typename?: 'Inspect', + dsl: Array, + response: Array, +}; + +export type IpOverviewData = { + __typename?: 'IpOverviewData', + client?: Maybe, + destination?: Maybe, + host: HostEcsFields, + server?: Maybe, + source?: Maybe, + inspect?: Maybe, +}; + +export type KpiHostDetailsData = { + __typename?: 'KpiHostDetailsData', + authSuccess?: Maybe, + authSuccessHistogram?: Maybe>, + authFailure?: Maybe, + authFailureHistogram?: Maybe>, + uniqueSourceIps?: Maybe, + uniqueSourceIpsHistogram?: Maybe>, + uniqueDestinationIps?: Maybe, + uniqueDestinationIpsHistogram?: Maybe>, + inspect?: Maybe, +}; + +export type KpiHostHistogramData = { + __typename?: 'KpiHostHistogramData', + x?: Maybe, + y?: Maybe, +}; + +export type KpiHostsData = { + __typename?: 'KpiHostsData', + hosts?: Maybe, + hostsHistogram?: Maybe>, + authSuccess?: Maybe, + authSuccessHistogram?: Maybe>, + authFailure?: Maybe, + authFailureHistogram?: Maybe>, + uniqueSourceIps?: Maybe, + uniqueSourceIpsHistogram?: Maybe>, + uniqueDestinationIps?: Maybe, + uniqueDestinationIpsHistogram?: Maybe>, + inspect?: Maybe, +}; + +export type KpiNetworkData = { + __typename?: 'KpiNetworkData', + networkEvents?: Maybe, + uniqueFlowId?: Maybe, + uniqueSourcePrivateIps?: Maybe, + uniqueSourcePrivateIpsHistogram?: Maybe>, + uniqueDestinationPrivateIps?: Maybe, + uniqueDestinationPrivateIpsHistogram?: Maybe>, + dnsQueries?: Maybe, + tlsHandshakes?: Maybe, + inspect?: Maybe, +}; + +export type KpiNetworkHistogramData = { + __typename?: 'KpiNetworkHistogramData', + x?: Maybe, + y?: Maybe, +}; + +export type KueryFilterQueryInput = { + kind?: Maybe, + expression?: Maybe, +}; + +export type KueryFilterQueryResult = { + __typename?: 'KueryFilterQueryResult', + kind?: Maybe, + expression?: Maybe, +}; + +export enum LastEventIndexKey { + hostDetails = 'hostDetails', + hosts = 'hosts', + ipDetails = 'ipDetails', + network = 'network' +} + +export type LastEventTimeData = { + __typename?: 'LastEventTimeData', + lastSeen?: Maybe, + inspect?: Maybe, +}; + +export type LastSourceHost = { + __typename?: 'LastSourceHost', + timestamp?: Maybe, + source?: Maybe, + host?: Maybe, +}; + +export type LastTimeDetails = { + hostName?: Maybe, + ip?: Maybe, +}; + +export type Location = { + __typename?: 'Location', + lon?: Maybe, + lat?: Maybe, +}; + +export type MatrixHistogramOverTimeData = { + __typename?: 'MatrixHistogramOverTimeData', + inspect?: Maybe, + matrixHistogramData: Array, + totalCount: Scalars['Float'], +}; + +export type MatrixOverOrdinalHistogramData = { + __typename?: 'MatrixOverOrdinalHistogramData', + x: Scalars['String'], + y: Scalars['Float'], + g: Scalars['String'], +}; + +export type MatrixOverTimeHistogramData = { + __typename?: 'MatrixOverTimeHistogramData', + x?: Maybe, + y?: Maybe, + g?: Maybe, +}; + +export type Mutation = { + __typename?: 'Mutation', + /** Persists a note */ + persistNote: ResponseNote, + deleteNote?: Maybe, + deleteNoteByTimelineId?: Maybe, + /** Persists a pinned event in a timeline */ + persistPinnedEventOnTimeline?: Maybe, + /** Remove a pinned events in a timeline */ + deletePinnedEventOnTimeline: Scalars['Boolean'], + /** Remove all pinned events in a timeline */ + deleteAllPinnedEventsOnTimeline: Scalars['Boolean'], + /** Persists a timeline */ + persistTimeline: ResponseTimeline, + persistFavorite: ResponseFavoriteTimeline, + deleteTimeline: Scalars['Boolean'], +}; + + +export type MutationPersistNoteArgs = { + noteId?: Maybe, + version?: Maybe, + note: NoteInput +}; + + +export type MutationDeleteNoteArgs = { + id: Array +}; + + +export type MutationDeleteNoteByTimelineIdArgs = { + timelineId: Scalars['ID'], + version?: Maybe +}; + + +export type MutationPersistPinnedEventOnTimelineArgs = { + pinnedEventId?: Maybe, + eventId: Scalars['ID'], + timelineId?: Maybe +}; + + +export type MutationDeletePinnedEventOnTimelineArgs = { + id: Array +}; + + +export type MutationDeleteAllPinnedEventsOnTimelineArgs = { + timelineId: Scalars['ID'] +}; + + +export type MutationPersistTimelineArgs = { + id?: Maybe, + version?: Maybe, + timeline: TimelineInput +}; + + +export type MutationPersistFavoriteArgs = { + timelineId?: Maybe +}; + + +export type MutationDeleteTimelineArgs = { + id: Array +}; + +export enum NetworkDirectionEcs { + inbound = 'inbound', + outbound = 'outbound', + internal = 'internal', + external = 'external', + incoming = 'incoming', + outgoing = 'outgoing', + listening = 'listening', + unknown = 'unknown' +} + +export type NetworkDnsData = { + __typename?: 'NetworkDnsData', + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, + histogram?: Maybe>, +}; + +export type NetworkDnsEdges = { + __typename?: 'NetworkDnsEdges', + node: NetworkDnsItem, + cursor: CursorType, +}; + +export enum NetworkDnsFields { + dnsName = 'dnsName', + queryCount = 'queryCount', + uniqueDomains = 'uniqueDomains', + dnsBytesIn = 'dnsBytesIn', + dnsBytesOut = 'dnsBytesOut' +} + +export type NetworkDnsItem = { + __typename?: 'NetworkDnsItem', + _id?: Maybe, + dnsBytesIn?: Maybe, + dnsBytesOut?: Maybe, + dnsName?: Maybe, + queryCount?: Maybe, + uniqueDomains?: Maybe, +}; + +export type NetworkDnsSortField = { + field: NetworkDnsFields, + direction: Direction, +}; + +export type NetworkDsOverTimeData = { + __typename?: 'NetworkDsOverTimeData', + inspect?: Maybe, + matrixHistogramData: Array, + totalCount: Scalars['Float'], +}; + +export type NetworkEcsField = { + __typename?: 'NetworkEcsField', + bytes?: Maybe, + community_id?: Maybe, + direction?: Maybe, + packets?: Maybe, + protocol?: Maybe, + transport?: Maybe, +}; + +export type NetworkHttpData = { + __typename?: 'NetworkHttpData', + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +}; + +export type NetworkHttpEdges = { + __typename?: 'NetworkHttpEdges', + node: NetworkHttpItem, + cursor: CursorType, +}; + +export enum NetworkHttpFields { + domains = 'domains', + lastHost = 'lastHost', + lastSourceIp = 'lastSourceIp', + methods = 'methods', + path = 'path', + requestCount = 'requestCount', + statuses = 'statuses' +} + +export type NetworkHttpItem = { + __typename?: 'NetworkHttpItem', + _id?: Maybe, + domains: Array, + lastHost?: Maybe, + lastSourceIp?: Maybe, + methods: Array, + path?: Maybe, + requestCount?: Maybe, + statuses: Array, +}; + +export type NetworkHttpSortField = { + direction: Direction, +}; + +export type NetworkTopCountriesData = { + __typename?: 'NetworkTopCountriesData', + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +}; + +export type NetworkTopCountriesEdges = { + __typename?: 'NetworkTopCountriesEdges', + node: NetworkTopCountriesItem, + cursor: CursorType, +}; + +export type NetworkTopCountriesItem = { + __typename?: 'NetworkTopCountriesItem', + _id?: Maybe, + source?: Maybe, + destination?: Maybe, + network?: Maybe, +}; + +export type NetworkTopNFlowData = { + __typename?: 'NetworkTopNFlowData', + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +}; + +export type NetworkTopNFlowEdges = { + __typename?: 'NetworkTopNFlowEdges', + node: NetworkTopNFlowItem, + cursor: CursorType, +}; + +export type NetworkTopNFlowItem = { + __typename?: 'NetworkTopNFlowItem', + _id?: Maybe, + source?: Maybe, + destination?: Maybe, + network?: Maybe, +}; + +export enum NetworkTopTablesFields { + bytes_in = 'bytes_in', + bytes_out = 'bytes_out', + flows = 'flows', + destination_ips = 'destination_ips', + source_ips = 'source_ips' +} + +export type NetworkTopTablesSortField = { + field: NetworkTopTablesFields, + direction: Direction, +}; + +export type NoteInput = { + eventId?: Maybe, + note?: Maybe, + timelineId?: Maybe, +}; + +export type NoteResult = { + __typename?: 'NoteResult', + eventId?: Maybe, + note?: Maybe, + timelineId?: Maybe, + noteId: Scalars['String'], + created?: Maybe, + createdBy?: Maybe, + timelineVersion?: Maybe, + updated?: Maybe, + updatedBy?: Maybe, + version?: Maybe, +}; + +export type OsEcsFields = { + __typename?: 'OsEcsFields', + platform?: Maybe, + name?: Maybe, + full?: Maybe, + family?: Maybe, + version?: Maybe, + kernel?: Maybe, +}; + +export type OsFields = { + __typename?: 'OsFields', + platform?: Maybe, + name?: Maybe, + full?: Maybe, + family?: Maybe, + version?: Maybe, + kernel?: Maybe, +}; + +export type Overview = { + __typename?: 'Overview', + firstSeen?: Maybe, + lastSeen?: Maybe, + autonomousSystem: AutonomousSystem, + geo: GeoEcsFields, +}; + +export type OverviewHostData = { + __typename?: 'OverviewHostData', + auditbeatAuditd?: Maybe, + auditbeatFIM?: Maybe, + auditbeatLogin?: Maybe, + auditbeatPackage?: Maybe, + auditbeatProcess?: Maybe, + auditbeatUser?: Maybe, + endgameDns?: Maybe, + endgameFile?: Maybe, + endgameImageLoad?: Maybe, + endgameNetwork?: Maybe, + endgameProcess?: Maybe, + endgameRegistry?: Maybe, + endgameSecurity?: Maybe, + filebeatSystemModule?: Maybe, + winlogbeatSecurity?: Maybe, + winlogbeatMWSysmonOperational?: Maybe, + inspect?: Maybe, +}; + +export type OverviewNetworkData = { + __typename?: 'OverviewNetworkData', + auditbeatSocket?: Maybe, + filebeatCisco?: Maybe, + filebeatNetflow?: Maybe, + filebeatPanw?: Maybe, + filebeatSuricata?: Maybe, + filebeatZeek?: Maybe, + packetbeatDNS?: Maybe, + packetbeatFlow?: Maybe, + packetbeatTLS?: Maybe, + inspect?: Maybe, +}; + +export type PackageEcsFields = { + __typename?: 'PackageEcsFields', + arch?: Maybe, + entity_id?: Maybe, + name?: Maybe, + size?: Maybe, + summary?: Maybe, + version?: Maybe, +}; + +export type PageInfo = { + __typename?: 'PageInfo', + endCursor?: Maybe, + hasNextPage?: Maybe, +}; + +export type PageInfoNote = { + pageIndex: Scalars['Float'], + pageSize: Scalars['Float'], +}; + +export type PageInfoPaginated = { + __typename?: 'PageInfoPaginated', + activePage: Scalars['Float'], + fakeTotalCount: Scalars['Float'], + showMorePagesIndicator: Scalars['Boolean'], +}; + +export type PageInfoTimeline = { + pageIndex: Scalars['Float'], + pageSize: Scalars['Float'], +}; + +export type PaginationInput = { + /** The limit parameter allows you to configure the maximum amount of items to be returned */ + limit: Scalars['Float'], + /** The cursor parameter defines the next result you want to fetch */ + cursor?: Maybe, + /** The tiebreaker parameter allow to be more precise to fetch the next item */ + tiebreaker?: Maybe, +}; + +export type PaginationInputPaginated = { + /** The activePage parameter defines the page of results you want to fetch */ + activePage: Scalars['Float'], + /** The cursorStart parameter defines the start of the results to be displayed */ + cursorStart: Scalars['Float'], + /** The fakePossibleCount parameter determines the total count in order to show 5 additional pages */ + fakePossibleCount: Scalars['Float'], + /** The querySize parameter is the number of items to be returned */ + querySize: Scalars['Float'], +}; + +export type PinnedEvent = { + __typename?: 'PinnedEvent', + code?: Maybe, + message?: Maybe, + pinnedEventId: Scalars['ID'], + eventId?: Maybe, + timelineId?: Maybe, + timelineVersion?: Maybe, + created?: Maybe, + createdBy?: Maybe, + updated?: Maybe, + updatedBy?: Maybe, + version?: Maybe, +}; + +export type PrimarySecondary = { + __typename?: 'PrimarySecondary', + primary?: Maybe, + secondary?: Maybe, + type?: Maybe, +}; + +export type ProcessEcsFields = { + __typename?: 'ProcessEcsFields', + hash?: Maybe, + pid?: Maybe, + name?: Maybe, + ppid?: Maybe, + args?: Maybe, + executable?: Maybe, + title?: Maybe, + thread?: Maybe, + working_directory?: Maybe, +}; + +export type ProcessHashData = { + __typename?: 'ProcessHashData', + md5?: Maybe, + sha1?: Maybe, + sha256?: Maybe, +}; + +export type Query = { + __typename?: 'Query', + getNote: NoteResult, + getNotesByTimelineId: Array, + getNotesByEventId: Array, + getAllNotes: ResponseNotes, + getAllPinnedEventsByTimelineId: Array, + /** Get a security data source by id */ + source: Source, + /** Get a list of all security data sources */ + allSources: Array, + getOneTimeline: TimelineResult, + getAllTimeline: ResponseTimelines, +}; + + +export type QueryGetNoteArgs = { + id: Scalars['ID'] +}; + + +export type QueryGetNotesByTimelineIdArgs = { + timelineId: Scalars['ID'] +}; + + +export type QueryGetNotesByEventIdArgs = { + eventId: Scalars['ID'] +}; + + +export type QueryGetAllNotesArgs = { + pageInfo?: Maybe, + search?: Maybe, + sort?: Maybe +}; + + +export type QueryGetAllPinnedEventsByTimelineIdArgs = { + timelineId: Scalars['ID'] +}; + + +export type QuerySourceArgs = { + id: Scalars['ID'] +}; + + +export type QueryGetOneTimelineArgs = { + id: Scalars['ID'] +}; + + +export type QueryGetAllTimelineArgs = { + pageInfo?: Maybe, + search?: Maybe, + sort?: Maybe, + onlyUserFavorite?: Maybe +}; + +export type QueryMatchInput = { + field?: Maybe, + displayField?: Maybe, + value?: Maybe, + displayValue?: Maybe, + operator?: Maybe, +}; + +export type QueryMatchResult = { + __typename?: 'QueryMatchResult', + field?: Maybe, + displayField?: Maybe, + value?: Maybe, + displayValue?: Maybe, + operator?: Maybe, +}; + +export type ResponseFavoriteTimeline = { + __typename?: 'ResponseFavoriteTimeline', + code?: Maybe, + message?: Maybe, + savedObjectId: Scalars['String'], + version: Scalars['String'], + favorite?: Maybe>, +}; + +export type ResponseNote = { + __typename?: 'ResponseNote', + code?: Maybe, + message?: Maybe, + note: NoteResult, +}; + +export type ResponseNotes = { + __typename?: 'ResponseNotes', + notes: Array, + totalCount?: Maybe, +}; + +export type ResponseTimeline = { + __typename?: 'ResponseTimeline', + code?: Maybe, + message?: Maybe, + timeline: TimelineResult, +}; + +export type ResponseTimelines = { + __typename?: 'ResponseTimelines', + timeline: Array>, + totalCount?: Maybe, +}; + +export type RuleEcsField = { + __typename?: 'RuleEcsField', + reference?: Maybe, +}; + +export type RuleField = { + __typename?: 'RuleField', + id?: Maybe, + rule_id?: Maybe, + false_positives: Array, + saved_id?: Maybe, + timeline_id?: Maybe, + timeline_title?: Maybe, + max_signals?: Maybe, + risk_score?: Maybe, + output_index?: Maybe, + description?: Maybe, + from?: Maybe, + immutable?: Maybe, + index?: Maybe, + interval?: Maybe, + language?: Maybe, + query?: Maybe, + references?: Maybe, + severity?: Maybe, + tags?: Maybe, + threat?: Maybe, + type?: Maybe, + size?: Maybe, + to?: Maybe, + enabled?: Maybe, + filters?: Maybe, + created_at?: Maybe, + updated_at?: Maybe, + created_by?: Maybe, + updated_by?: Maybe, + version?: Maybe, +}; + +export type SayMyName = { + __typename?: 'SayMyName', + /** The id of the source */ + appName: Scalars['String'], +}; + +export type SerializedFilterQueryInput = { + filterQuery?: Maybe, +}; + +export type SerializedFilterQueryResult = { + __typename?: 'SerializedFilterQueryResult', + filterQuery?: Maybe, +}; + +export type SerializedKueryQueryInput = { + kuery?: Maybe, + serializedQuery?: Maybe, +}; + +export type SerializedKueryQueryResult = { + __typename?: 'SerializedKueryQueryResult', + kuery?: Maybe, + serializedQuery?: Maybe, +}; + +export type SignalField = { + __typename?: 'SignalField', + rule?: Maybe, + original_time?: Maybe, +}; + +export type SortField = { + sortFieldId: Scalars['String'], + direction: Direction, +}; + +export enum SortFieldNote { + updatedBy = 'updatedBy', + updated = 'updated' +} + +export enum SortFieldTimeline { + title = 'title', + description = 'description', + updated = 'updated', + created = 'created' +} + +export type SortNote = { + sortField: SortFieldNote, + sortOrder: Direction, +}; + +export type SortTimeline = { + sortField: SortFieldTimeline, + sortOrder: Direction, +}; + +export type SortTimelineInput = { + columnId?: Maybe, + sortDirection?: Maybe, +}; + +export type SortTimelineResult = { + __typename?: 'SortTimelineResult', + columnId?: Maybe, + sortDirection?: Maybe, +}; + +export type Source = { + __typename?: 'Source', + /** The id of the source */ + id: Scalars['ID'], + /** The raw configuration of the source */ + configuration: SourceConfiguration, + /** The status of the source */ + status: SourceStatus, + /** Gets Authentication success and failures based on a timerange */ + Authentications: AuthenticationsData, + Timeline: TimelineData, + TimelineDetails: TimelineDetailsData, + LastEventTime: LastEventTimeData, + /** Gets Hosts based on timerange and specified criteria, or all events in the timerange if no criteria is specified */ + Hosts: HostsData, + HostOverview: HostItem, + HostFirstLastSeen: FirstLastSeenHost, + IpOverview?: Maybe, + Users: UsersData, + KpiNetwork?: Maybe, + KpiHosts: KpiHostsData, + KpiHostDetails: KpiHostDetailsData, + MatrixHistogram: MatrixHistogramOverTimeData, + NetworkTopCountries: NetworkTopCountriesData, + NetworkTopNFlow: NetworkTopNFlowData, + NetworkDns: NetworkDnsData, + NetworkDnsHistogram: NetworkDsOverTimeData, + NetworkHttp: NetworkHttpData, + OverviewNetwork?: Maybe, + OverviewHost?: Maybe, + Tls: TlsData, + /** Gets UncommonProcesses based on a timerange, or all UncommonProcesses if no criteria is specified */ + UncommonProcesses: UncommonProcessesData, + /** Just a simple example to get the app name */ + whoAmI?: Maybe, +}; + + +export type SourceAuthenticationsArgs = { + timerange: TimerangeInput, + pagination: PaginationInputPaginated, + filterQuery?: Maybe, + defaultIndex: Array +}; + + +export type SourceTimelineArgs = { + pagination: PaginationInput, + sortField: SortField, + fieldRequested: Array, + timerange?: Maybe, + filterQuery?: Maybe, + defaultIndex: Array +}; + + +export type SourceTimelineDetailsArgs = { + eventId: Scalars['String'], + indexName: Scalars['String'], + defaultIndex: Array +}; + + +export type SourceLastEventTimeArgs = { + id?: Maybe, + indexKey: LastEventIndexKey, + details: LastTimeDetails, + defaultIndex: Array +}; + + +export type SourceHostsArgs = { + id?: Maybe, + timerange: TimerangeInput, + pagination: PaginationInputPaginated, + sort: HostsSortField, + filterQuery?: Maybe, + defaultIndex: Array +}; + + +export type SourceHostOverviewArgs = { + id?: Maybe, + hostName: Scalars['String'], + timerange: TimerangeInput, + defaultIndex: Array +}; + + +export type SourceHostFirstLastSeenArgs = { + id?: Maybe, + hostName: Scalars['String'], + defaultIndex: Array +}; + + +export type SourceIpOverviewArgs = { + id?: Maybe, + filterQuery?: Maybe, + ip: Scalars['String'], + defaultIndex: Array +}; + + +export type SourceUsersArgs = { + filterQuery?: Maybe, + id?: Maybe, + ip: Scalars['String'], + pagination: PaginationInputPaginated, + sort: UsersSortField, + flowTarget: FlowTarget, + timerange: TimerangeInput, + defaultIndex: Array +}; + + +export type SourceKpiNetworkArgs = { + id?: Maybe, + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array +}; + + +export type SourceKpiHostsArgs = { + id?: Maybe, + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array +}; + + +export type SourceKpiHostDetailsArgs = { + id?: Maybe, + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array +}; + + +export type SourceMatrixHistogramArgs = { + filterQuery?: Maybe, + defaultIndex: Array, + timerange: TimerangeInput, + stackByField: Scalars['String'], + histogramType: HistogramType +}; + + +export type SourceNetworkTopCountriesArgs = { + id?: Maybe, + filterQuery?: Maybe, + ip?: Maybe, + flowTarget: FlowTargetSourceDest, + pagination: PaginationInputPaginated, + sort: NetworkTopTablesSortField, + timerange: TimerangeInput, + defaultIndex: Array +}; + + +export type SourceNetworkTopNFlowArgs = { + id?: Maybe, + filterQuery?: Maybe, + ip?: Maybe, + flowTarget: FlowTargetSourceDest, + pagination: PaginationInputPaginated, + sort: NetworkTopTablesSortField, + timerange: TimerangeInput, + defaultIndex: Array +}; + + +export type SourceNetworkDnsArgs = { + filterQuery?: Maybe, + id?: Maybe, + isPtrIncluded: Scalars['Boolean'], + pagination: PaginationInputPaginated, + sort: NetworkDnsSortField, + stackByField?: Maybe, + timerange: TimerangeInput, + defaultIndex: Array +}; + + +export type SourceNetworkDnsHistogramArgs = { + filterQuery?: Maybe, + defaultIndex: Array, + timerange: TimerangeInput, + stackByField?: Maybe +}; + + +export type SourceNetworkHttpArgs = { + id?: Maybe, + filterQuery?: Maybe, + ip?: Maybe, + pagination: PaginationInputPaginated, + sort: NetworkHttpSortField, + timerange: TimerangeInput, + defaultIndex: Array +}; + + +export type SourceOverviewNetworkArgs = { + id?: Maybe, + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array +}; + + +export type SourceOverviewHostArgs = { + id?: Maybe, + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array +}; + + +export type SourceTlsArgs = { + filterQuery?: Maybe, + id?: Maybe, + ip: Scalars['String'], + pagination: PaginationInputPaginated, + sort: TlsSortField, + flowTarget: FlowTargetSourceDest, + timerange: TimerangeInput, + defaultIndex: Array +}; + + +export type SourceUncommonProcessesArgs = { + timerange: TimerangeInput, + pagination: PaginationInputPaginated, + filterQuery?: Maybe, + defaultIndex: Array +}; + +/** A set of configuration options for a security data source */ +export type SourceConfiguration = { + __typename?: 'SourceConfiguration', + /** The field mapping to use for this source */ + fields: SourceFields, +}; + +export type SourceEcsFields = { + __typename?: 'SourceEcsFields', + bytes?: Maybe, + ip?: Maybe, + port?: Maybe, + domain?: Maybe, + geo?: Maybe, + packets?: Maybe, +}; + +/** A mapping of semantic fields to their document counterparts */ +export type SourceFields = { + __typename?: 'SourceFields', + /** The field to identify a container by */ + container: Scalars['String'], + /** The fields to identify a host by */ + host: Scalars['String'], + /** The fields that may contain the log event message. The first field found win. */ + message: Array, + /** The field to identify a pod by */ + pod: Scalars['String'], + /** The field to use as a tiebreaker for log events that have identical timestamps */ + tiebreaker: Scalars['String'], + /** The field to use as a timestamp for metrics and logs */ + timestamp: Scalars['String'], +}; + +/** The status of an infrastructure data source */ +export type SourceStatus = { + __typename?: 'SourceStatus', + /** Whether the configured alias or wildcard pattern resolve to any auditbeat indices */ + indicesExist: Scalars['Boolean'], + /** The list of fields defined in the index mappings */ + indexFields: Array, +}; + + +/** The status of an infrastructure data source */ +export type SourceStatusIndicesExistArgs = { + defaultIndex: Array +}; + + +/** The status of an infrastructure data source */ +export type SourceStatusIndexFieldsArgs = { + defaultIndex: Array +}; + +export type SshEcsFields = { + __typename?: 'SshEcsFields', + method?: Maybe, + signature?: Maybe, +}; + +export type Summary = { + __typename?: 'Summary', + actor?: Maybe, + object?: Maybe, + how?: Maybe, + message_type?: Maybe, + sequence?: Maybe, +}; + +export type SuricataAlertData = { + __typename?: 'SuricataAlertData', + signature?: Maybe, + signature_id?: Maybe, +}; + +export type SuricataEcsFields = { + __typename?: 'SuricataEcsFields', + eve?: Maybe, +}; + +export type SuricataEveData = { + __typename?: 'SuricataEveData', + alert?: Maybe, + flow_id?: Maybe, + proto?: Maybe, +}; + +export type SystemEcsField = { + __typename?: 'SystemEcsField', + audit?: Maybe, + auth?: Maybe, +}; + +export type Thread = { + __typename?: 'Thread', + id?: Maybe, + start?: Maybe, +}; + +export type TimelineData = { + __typename?: 'TimelineData', + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfo, + inspect?: Maybe, +}; + +export type TimelineDetailsData = { + __typename?: 'TimelineDetailsData', + data?: Maybe>, + inspect?: Maybe, +}; + +export type TimelineEdges = { + __typename?: 'TimelineEdges', + node: TimelineItem, + cursor: CursorType, +}; + +export type TimelineInput = { + columns?: Maybe>, + dataProviders?: Maybe>, + description?: Maybe, + eventType?: Maybe, + filters?: Maybe>, + kqlMode?: Maybe, + kqlQuery?: Maybe, + title?: Maybe, + dateRange?: Maybe, + savedQueryId?: Maybe, + sort?: Maybe, +}; + +export type TimelineItem = { + __typename?: 'TimelineItem', + _id: Scalars['String'], + _index?: Maybe, + data: Array, + ecs: Ecs, +}; + +export type TimelineNonEcsData = { + __typename?: 'TimelineNonEcsData', + field: Scalars['String'], + value?: Maybe, +}; + +export type TimelineResult = { + __typename?: 'TimelineResult', + columns?: Maybe>, + created?: Maybe, + createdBy?: Maybe, + dataProviders?: Maybe>, + dateRange?: Maybe, + description?: Maybe, + eventIdToNoteIds?: Maybe>, + eventType?: Maybe, + favorite?: Maybe>, + filters?: Maybe>, + kqlMode?: Maybe, + kqlQuery?: Maybe, + notes?: Maybe>, + noteIds?: Maybe>, + pinnedEventIds?: Maybe>, + pinnedEventsSaveObject?: Maybe>, + savedQueryId?: Maybe, + savedObjectId: Scalars['String'], + sort?: Maybe, + title?: Maybe, + updated?: Maybe, + updatedBy?: Maybe, + version: Scalars['String'], +}; + +export type TimerangeInput = { + /** + * The interval string to use for last bucket. The format is '{value}{unit}'. For + * example '5m' would return the metrics for the last 5 minutes of the timespan. + */ + interval: Scalars['String'], + /** The end of the timerange */ + to: Scalars['Float'], + /** The beginning of the timerange */ + from: Scalars['Float'], +}; + +export type TlsClientCertificateData = { + __typename?: 'TlsClientCertificateData', + fingerprint?: Maybe, +}; + +export type TlsData = { + __typename?: 'TlsData', + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +}; + +export type TlsEcsFields = { + __typename?: 'TlsEcsFields', + client_certificate?: Maybe, + fingerprints?: Maybe, + server_certificate?: Maybe, +}; + +export type TlsEdges = { + __typename?: 'TlsEdges', + node: TlsNode, + cursor: CursorType, +}; + +export enum TlsFields { + _id = '_id' +} + +export type TlsFingerprintsData = { + __typename?: 'TlsFingerprintsData', + ja3?: Maybe, +}; + +export type TlsJa3Data = { + __typename?: 'TlsJa3Data', + hash?: Maybe, +}; + +export type TlsNode = { + __typename?: 'TlsNode', + _id?: Maybe, + timestamp?: Maybe, + alternativeNames?: Maybe>, + notAfter?: Maybe>, + commonNames?: Maybe>, + ja3?: Maybe>, + issuerNames?: Maybe>, +}; + +export type TlsServerCertificateData = { + __typename?: 'TlsServerCertificateData', + fingerprint?: Maybe, +}; + +export type TlsSortField = { + field: TlsFields, + direction: Direction, +}; + + + + + +export type TopCountriesItemDestination = { + __typename?: 'TopCountriesItemDestination', + country?: Maybe, + destination_ips?: Maybe, + flows?: Maybe, + location?: Maybe, + source_ips?: Maybe, +}; + +export type TopCountriesItemSource = { + __typename?: 'TopCountriesItemSource', + country?: Maybe, + destination_ips?: Maybe, + flows?: Maybe, + location?: Maybe, + source_ips?: Maybe, +}; + +export type TopNetworkTablesEcsField = { + __typename?: 'TopNetworkTablesEcsField', + bytes_in?: Maybe, + bytes_out?: Maybe, +}; + +export type TopNFlowItemDestination = { + __typename?: 'TopNFlowItemDestination', + autonomous_system?: Maybe, + domain?: Maybe>, + ip?: Maybe, + location?: Maybe, + flows?: Maybe, + source_ips?: Maybe, +}; + +export type TopNFlowItemSource = { + __typename?: 'TopNFlowItemSource', + autonomous_system?: Maybe, + domain?: Maybe>, + ip?: Maybe, + location?: Maybe, + flows?: Maybe, + destination_ips?: Maybe, +}; + + +export type UncommonProcessesData = { + __typename?: 'UncommonProcessesData', + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +}; + +export type UncommonProcessesEdges = { + __typename?: 'UncommonProcessesEdges', + node: UncommonProcessItem, + cursor: CursorType, +}; + +export type UncommonProcessItem = { + __typename?: 'UncommonProcessItem', + _id: Scalars['String'], + instances: Scalars['Float'], + process: ProcessEcsFields, + hosts: Array, + user?: Maybe, +}; + +export type UrlEcsFields = { + __typename?: 'UrlEcsFields', + domain?: Maybe, + original?: Maybe, + username?: Maybe, + password?: Maybe, +}; + +export type UserEcsFields = { + __typename?: 'UserEcsFields', + domain?: Maybe, + id?: Maybe, + name?: Maybe, + full_name?: Maybe, + email?: Maybe, + hash?: Maybe, + group?: Maybe, +}; + +export type UsersData = { + __typename?: 'UsersData', + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +}; + +export type UsersEdges = { + __typename?: 'UsersEdges', + node: UsersNode, + cursor: CursorType, +}; + +export enum UsersFields { + name = 'name', + count = 'count' +} + +export type UsersItem = { + __typename?: 'UsersItem', + name?: Maybe, + id?: Maybe, + groupId?: Maybe, + groupName?: Maybe, + count?: Maybe, +}; + +export type UsersNode = { + __typename?: 'UsersNode', + _id?: Maybe, + timestamp?: Maybe, + user?: Maybe, +}; + +export type UsersSortField = { + field: UsersFields, + direction: Direction, +}; + +export type WinlogEcsFields = { + __typename?: 'WinlogEcsFields', + event_id?: Maybe, +}; + +export type ZeekConnectionData = { + __typename?: 'ZeekConnectionData', + local_resp?: Maybe, + local_orig?: Maybe, + missed_bytes?: Maybe, + state?: Maybe, + history?: Maybe, +}; + +export type ZeekDnsData = { + __typename?: 'ZeekDnsData', + AA?: Maybe, + qclass_name?: Maybe, + RD?: Maybe, + qtype_name?: Maybe, + rejected?: Maybe, + qtype?: Maybe, + query?: Maybe, + trans_id?: Maybe, + qclass?: Maybe, + RA?: Maybe, + TC?: Maybe, +}; + +export type ZeekEcsFields = { + __typename?: 'ZeekEcsFields', + session_id?: Maybe, + connection?: Maybe, + notice?: Maybe, + dns?: Maybe, + http?: Maybe, + files?: Maybe, + ssl?: Maybe, +}; + +export type ZeekFileData = { + __typename?: 'ZeekFileData', + session_ids?: Maybe, + timedout?: Maybe, + local_orig?: Maybe, + tx_host?: Maybe, + source?: Maybe, + is_orig?: Maybe, + overflow_bytes?: Maybe, + sha1?: Maybe, + duration?: Maybe, + depth?: Maybe, + analyzers?: Maybe, + mime_type?: Maybe, + rx_host?: Maybe, + total_bytes?: Maybe, + fuid?: Maybe, + seen_bytes?: Maybe, + missing_bytes?: Maybe, + md5?: Maybe, +}; + +export type ZeekHttpData = { + __typename?: 'ZeekHttpData', + resp_mime_types?: Maybe, + trans_depth?: Maybe, + status_msg?: Maybe, + resp_fuids?: Maybe, + tags?: Maybe, +}; + +export type ZeekNoticeData = { + __typename?: 'ZeekNoticeData', + suppress_for?: Maybe, + msg?: Maybe, + note?: Maybe, + sub?: Maybe, + dst?: Maybe, + dropped?: Maybe, + peer_descr?: Maybe, +}; + +export type ZeekSslData = { + __typename?: 'ZeekSslData', + cipher?: Maybe, + established?: Maybe, + resumed?: Maybe, + version?: Maybe, +}; + +export type GetAuthenticationsQueryQueryVariables = { + sourceId: Scalars['ID'], + timerange: TimerangeInput, + pagination: PaginationInputPaginated, + filterQuery?: Maybe, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetAuthenticationsQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, Authentications: { __typename?: 'AuthenticationsData', totalCount: number, edges: Array<{ __typename?: 'AuthenticationsEdges', node: { __typename?: 'AuthenticationItem', _id: string, failures: number, successes: number, user: { __typename?: 'UserEcsFields', name: Maybe }, lastSuccess: Maybe<{ __typename?: 'LastSourceHost', timestamp: Maybe, source: Maybe<{ __typename?: 'SourceEcsFields', ip: Maybe }>, host: Maybe<{ __typename?: 'HostEcsFields', id: Maybe, name: Maybe }> }>, lastFailure: Maybe<{ __typename?: 'LastSourceHost', timestamp: Maybe, source: Maybe<{ __typename?: 'SourceEcsFields', ip: Maybe }>, host: Maybe<{ __typename?: 'HostEcsFields', id: Maybe, name: Maybe }> }> }, cursor: { __typename?: 'CursorType', value: Maybe } }>, pageInfo: { __typename?: 'PageInfoPaginated', activePage: number, fakeTotalCount: number, showMorePagesIndicator: boolean }, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export type GetLastEventTimeQueryQueryVariables = { + sourceId: Scalars['ID'], + indexKey: LastEventIndexKey, + details: LastTimeDetails, + defaultIndex: Array +}; + + +export type GetLastEventTimeQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, LastEventTime: { __typename?: 'LastEventTimeData', lastSeen: Maybe } } }; + +export type GetHostFirstLastSeenQueryQueryVariables = { + sourceId: Scalars['ID'], + hostName: Scalars['String'], + defaultIndex: Array +}; + + +export type GetHostFirstLastSeenQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, HostFirstLastSeen: { __typename?: 'FirstLastSeenHost', firstSeen: Maybe, lastSeen: Maybe } } }; + +export type GetHostsTableQueryQueryVariables = { + sourceId: Scalars['ID'], + timerange: TimerangeInput, + pagination: PaginationInputPaginated, + sort: HostsSortField, + filterQuery?: Maybe, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetHostsTableQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, Hosts: { __typename?: 'HostsData', totalCount: number, edges: Array<{ __typename?: 'HostsEdges', node: { __typename?: 'HostItem', _id: Maybe, lastSeen: Maybe, host: Maybe<{ __typename?: 'HostEcsFields', id: Maybe, name: Maybe, os: Maybe<{ __typename?: 'OsEcsFields', name: Maybe, version: Maybe }> }> }, cursor: { __typename?: 'CursorType', value: Maybe } }>, pageInfo: { __typename?: 'PageInfoPaginated', activePage: number, fakeTotalCount: number, showMorePagesIndicator: boolean }, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export type GetHostOverviewQueryQueryVariables = { + sourceId: Scalars['ID'], + hostName: Scalars['String'], + timerange: TimerangeInput, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetHostOverviewQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, HostOverview: { __typename?: 'HostItem', _id: Maybe, host: Maybe<{ __typename?: 'HostEcsFields', architecture: Maybe, id: Maybe, ip: Maybe, mac: Maybe, name: Maybe, type: Maybe, os: Maybe<{ __typename?: 'OsEcsFields', family: Maybe, name: Maybe, platform: Maybe, version: Maybe }> }>, cloud: Maybe<{ __typename?: 'CloudFields', provider: Maybe>>, region: Maybe>>, instance: Maybe<{ __typename?: 'CloudInstance', id: Maybe>> }>, machine: Maybe<{ __typename?: 'CloudMachine', type: Maybe>> }> }>, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export type GetIpOverviewQueryQueryVariables = { + sourceId: Scalars['ID'], + filterQuery?: Maybe, + ip: Scalars['String'], + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetIpOverviewQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, IpOverview: Maybe<{ __typename?: 'IpOverviewData', source: Maybe<{ __typename?: 'Overview', firstSeen: Maybe, lastSeen: Maybe, autonomousSystem: { __typename?: 'AutonomousSystem', number: Maybe, organization: Maybe<{ __typename?: 'AutonomousSystemOrganization', name: Maybe }> }, geo: { __typename?: 'GeoEcsFields', continent_name: Maybe, city_name: Maybe, country_iso_code: Maybe, country_name: Maybe, region_iso_code: Maybe, region_name: Maybe, location: Maybe<{ __typename?: 'Location', lat: Maybe, lon: Maybe }> } }>, destination: Maybe<{ __typename?: 'Overview', firstSeen: Maybe, lastSeen: Maybe, autonomousSystem: { __typename?: 'AutonomousSystem', number: Maybe, organization: Maybe<{ __typename?: 'AutonomousSystemOrganization', name: Maybe }> }, geo: { __typename?: 'GeoEcsFields', continent_name: Maybe, city_name: Maybe, country_iso_code: Maybe, country_name: Maybe, region_iso_code: Maybe, region_name: Maybe, location: Maybe<{ __typename?: 'Location', lat: Maybe, lon: Maybe }> } }>, host: { __typename?: 'HostEcsFields', architecture: Maybe, id: Maybe, ip: Maybe, mac: Maybe, name: Maybe, type: Maybe, os: Maybe<{ __typename?: 'OsEcsFields', family: Maybe, name: Maybe, platform: Maybe, version: Maybe }> }, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> }> } }; + +export type KpiHostDetailsChartFieldsFragment = { __typename?: 'KpiHostHistogramData', x: Maybe, y: Maybe }; + +export type GetKpiHostDetailsQueryQueryVariables = { + sourceId: Scalars['ID'], + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetKpiHostDetailsQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, KpiHostDetails: { __typename?: 'KpiHostDetailsData', authSuccess: Maybe, authFailure: Maybe, uniqueSourceIps: Maybe, uniqueDestinationIps: Maybe, authSuccessHistogram: Maybe>, authFailureHistogram: Maybe>, uniqueSourceIpsHistogram: Maybe>, uniqueDestinationIpsHistogram: Maybe>, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export type KpiHostChartFieldsFragment = { __typename?: 'KpiHostHistogramData', x: Maybe, y: Maybe }; + +export type GetKpiHostsQueryQueryVariables = { + sourceId: Scalars['ID'], + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetKpiHostsQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, KpiHosts: { __typename?: 'KpiHostsData', hosts: Maybe, authSuccess: Maybe, authFailure: Maybe, uniqueSourceIps: Maybe, uniqueDestinationIps: Maybe, hostsHistogram: Maybe>, authSuccessHistogram: Maybe>, authFailureHistogram: Maybe>, uniqueSourceIpsHistogram: Maybe>, uniqueDestinationIpsHistogram: Maybe>, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export type KpiNetworkChartFieldsFragment = { __typename?: 'KpiNetworkHistogramData', x: Maybe, y: Maybe }; + +export type GetKpiNetworkQueryQueryVariables = { + sourceId: Scalars['ID'], + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetKpiNetworkQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, KpiNetwork: Maybe<{ __typename?: 'KpiNetworkData', networkEvents: Maybe, uniqueFlowId: Maybe, uniqueSourcePrivateIps: Maybe, uniqueDestinationPrivateIps: Maybe, dnsQueries: Maybe, tlsHandshakes: Maybe, uniqueSourcePrivateIpsHistogram: Maybe>, uniqueDestinationPrivateIpsHistogram: Maybe>, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> }> } }; + +export type GetMatrixHistogramQueryQueryVariables = { + defaultIndex: Array, + filterQuery?: Maybe, + histogramType: HistogramType, + inspect: Scalars['Boolean'], + sourceId: Scalars['ID'], + stackByField: Scalars['String'], + timerange: TimerangeInput +}; + + +export type GetMatrixHistogramQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, MatrixHistogram: { __typename?: 'MatrixHistogramOverTimeData', totalCount: number, matrixHistogramData: Array<{ __typename?: 'MatrixOverTimeHistogramData', x: Maybe, y: Maybe, g: Maybe }>, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export type GetNetworkDnsQueryQueryVariables = { + defaultIndex: Array, + filterQuery?: Maybe, + inspect: Scalars['Boolean'], + isPtrIncluded: Scalars['Boolean'], + pagination: PaginationInputPaginated, + sort: NetworkDnsSortField, + sourceId: Scalars['ID'], + stackByField?: Maybe, + timerange: TimerangeInput +}; + + +export type GetNetworkDnsQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, NetworkDns: { __typename?: 'NetworkDnsData', totalCount: number, edges: Array<{ __typename?: 'NetworkDnsEdges', node: { __typename?: 'NetworkDnsItem', _id: Maybe, dnsBytesIn: Maybe, dnsBytesOut: Maybe, dnsName: Maybe, queryCount: Maybe, uniqueDomains: Maybe }, cursor: { __typename?: 'CursorType', value: Maybe } }>, pageInfo: { __typename?: 'PageInfoPaginated', activePage: number, fakeTotalCount: number, showMorePagesIndicator: boolean }, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export type GetNetworkHttpQueryQueryVariables = { + sourceId: Scalars['ID'], + ip?: Maybe, + filterQuery?: Maybe, + pagination: PaginationInputPaginated, + sort: NetworkHttpSortField, + timerange: TimerangeInput, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetNetworkHttpQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, NetworkHttp: { __typename?: 'NetworkHttpData', totalCount: number, edges: Array<{ __typename?: 'NetworkHttpEdges', node: { __typename?: 'NetworkHttpItem', domains: Array, lastHost: Maybe, lastSourceIp: Maybe, methods: Array, path: Maybe, requestCount: Maybe, statuses: Array }, cursor: { __typename?: 'CursorType', value: Maybe } }>, pageInfo: { __typename?: 'PageInfoPaginated', activePage: number, fakeTotalCount: number, showMorePagesIndicator: boolean }, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export type GetNetworkTopCountriesQueryQueryVariables = { + sourceId: Scalars['ID'], + ip?: Maybe, + filterQuery?: Maybe, + pagination: PaginationInputPaginated, + sort: NetworkTopTablesSortField, + flowTarget: FlowTargetSourceDest, + timerange: TimerangeInput, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetNetworkTopCountriesQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, NetworkTopCountries: { __typename?: 'NetworkTopCountriesData', totalCount: number, edges: Array<{ __typename?: 'NetworkTopCountriesEdges', node: { __typename?: 'NetworkTopCountriesItem', source: Maybe<{ __typename?: 'TopCountriesItemSource', country: Maybe, destination_ips: Maybe, flows: Maybe, source_ips: Maybe }>, destination: Maybe<{ __typename?: 'TopCountriesItemDestination', country: Maybe, destination_ips: Maybe, flows: Maybe, source_ips: Maybe }>, network: Maybe<{ __typename?: 'TopNetworkTablesEcsField', bytes_in: Maybe, bytes_out: Maybe }> }, cursor: { __typename?: 'CursorType', value: Maybe } }>, pageInfo: { __typename?: 'PageInfoPaginated', activePage: number, fakeTotalCount: number, showMorePagesIndicator: boolean }, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export type GetNetworkTopNFlowQueryQueryVariables = { + sourceId: Scalars['ID'], + ip?: Maybe, + filterQuery?: Maybe, + pagination: PaginationInputPaginated, + sort: NetworkTopTablesSortField, + flowTarget: FlowTargetSourceDest, + timerange: TimerangeInput, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetNetworkTopNFlowQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, NetworkTopNFlow: { __typename?: 'NetworkTopNFlowData', totalCount: number, edges: Array<{ __typename?: 'NetworkTopNFlowEdges', node: { __typename?: 'NetworkTopNFlowItem', source: Maybe<{ __typename?: 'TopNFlowItemSource', domain: Maybe>, ip: Maybe, flows: Maybe, destination_ips: Maybe, autonomous_system: Maybe<{ __typename?: 'AutonomousSystemItem', name: Maybe, number: Maybe }>, location: Maybe<{ __typename?: 'GeoItem', flowTarget: Maybe, geo: Maybe<{ __typename?: 'GeoEcsFields', continent_name: Maybe, country_name: Maybe, country_iso_code: Maybe, city_name: Maybe, region_iso_code: Maybe, region_name: Maybe }> }> }>, destination: Maybe<{ __typename?: 'TopNFlowItemDestination', domain: Maybe>, ip: Maybe, flows: Maybe, source_ips: Maybe, autonomous_system: Maybe<{ __typename?: 'AutonomousSystemItem', name: Maybe, number: Maybe }>, location: Maybe<{ __typename?: 'GeoItem', flowTarget: Maybe, geo: Maybe<{ __typename?: 'GeoEcsFields', continent_name: Maybe, country_name: Maybe, country_iso_code: Maybe, city_name: Maybe, region_iso_code: Maybe, region_name: Maybe }> }> }>, network: Maybe<{ __typename?: 'TopNetworkTablesEcsField', bytes_in: Maybe, bytes_out: Maybe }> }, cursor: { __typename?: 'CursorType', value: Maybe } }>, pageInfo: { __typename?: 'PageInfoPaginated', activePage: number, fakeTotalCount: number, showMorePagesIndicator: boolean }, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export type GetOverviewHostQueryQueryVariables = { + sourceId: Scalars['ID'], + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetOverviewHostQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, OverviewHost: Maybe<{ __typename?: 'OverviewHostData', auditbeatAuditd: Maybe, auditbeatFIM: Maybe, auditbeatLogin: Maybe, auditbeatPackage: Maybe, auditbeatProcess: Maybe, auditbeatUser: Maybe, endgameDns: Maybe, endgameFile: Maybe, endgameImageLoad: Maybe, endgameNetwork: Maybe, endgameProcess: Maybe, endgameRegistry: Maybe, endgameSecurity: Maybe, filebeatSystemModule: Maybe, winlogbeatSecurity: Maybe, winlogbeatMWSysmonOperational: Maybe, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> }> } }; + +export type GetOverviewNetworkQueryQueryVariables = { + sourceId: Scalars['ID'], + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetOverviewNetworkQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, OverviewNetwork: Maybe<{ __typename?: 'OverviewNetworkData', auditbeatSocket: Maybe, filebeatCisco: Maybe, filebeatNetflow: Maybe, filebeatPanw: Maybe, filebeatSuricata: Maybe, filebeatZeek: Maybe, packetbeatDNS: Maybe, packetbeatFlow: Maybe, packetbeatTLS: Maybe, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> }> } }; + +export type SourceQueryQueryVariables = { + sourceId?: Maybe, + defaultIndex: Array +}; + + +export type SourceQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, status: { __typename?: 'SourceStatus', indicesExist: boolean, indexFields: Array<{ __typename?: 'IndexField', category: string, description: Maybe, example: Maybe, indexes: Array>, name: string, searchable: boolean, type: string, aggregatable: boolean, format: Maybe }> } } }; + +export type GetAllTimelineQueryVariables = { + pageInfo: PageInfoTimeline, + search?: Maybe, + sort?: Maybe, + onlyUserFavorite?: Maybe +}; + + +export type GetAllTimelineQuery = { __typename?: 'Query', getAllTimeline: { __typename?: 'ResponseTimelines', totalCount: Maybe, timeline: Array, noteIds: Maybe>, pinnedEventIds: Maybe>, title: Maybe, created: Maybe, createdBy: Maybe, updated: Maybe, updatedBy: Maybe, version: string, favorite: Maybe, userName: Maybe, favoriteDate: Maybe }>>, eventIdToNoteIds: Maybe, note: Maybe, timelineId: Maybe, noteId: string, created: Maybe, createdBy: Maybe, timelineVersion: Maybe, updated: Maybe, updatedBy: Maybe, version: Maybe }>>, notes: Maybe, note: Maybe, timelineId: Maybe, timelineVersion: Maybe, noteId: string, created: Maybe, createdBy: Maybe, updated: Maybe, updatedBy: Maybe, version: Maybe }>> }>> } }; + +export type DeleteTimelineMutationMutationVariables = { + id: Array +}; + + +export type DeleteTimelineMutationMutation = { __typename?: 'Mutation', deleteTimeline: boolean }; + +export type GetTimelineDetailsQueryQueryVariables = { + sourceId: Scalars['ID'], + eventId: Scalars['String'], + indexName: Scalars['String'], + defaultIndex: Array +}; + + +export type GetTimelineDetailsQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, TimelineDetails: { __typename?: 'TimelineDetailsData', data: Maybe, originalValue: Maybe }>> } } }; + +export type PersistTimelineFavoriteMutationMutationVariables = { + timelineId?: Maybe +}; + + +export type PersistTimelineFavoriteMutationMutation = { __typename?: 'Mutation', persistFavorite: { __typename?: 'ResponseFavoriteTimeline', savedObjectId: string, version: string, favorite: Maybe, userName: Maybe, favoriteDate: Maybe }>> } }; + +export type GetTimelineQueryQueryVariables = { + sourceId: Scalars['ID'], + fieldRequested: Array, + pagination: PaginationInput, + sortField: SortField, + filterQuery?: Maybe, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetTimelineQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, Timeline: { __typename?: 'TimelineData', totalCount: number, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }>, pageInfo: { __typename?: 'PageInfo', hasNextPage: Maybe, endCursor: Maybe<{ __typename?: 'CursorType', value: Maybe, tiebreaker: Maybe }> }, edges: Array<{ __typename?: 'TimelineEdges', node: { __typename?: 'TimelineItem', _id: string, _index: Maybe, data: Array<{ __typename?: 'TimelineNonEcsData', field: string, value: Maybe }>, ecs: { __typename?: 'ECS', _id: string, _index: Maybe, timestamp: Maybe, message: Maybe, system: Maybe<{ __typename?: 'SystemEcsField', auth: Maybe<{ __typename?: 'AuthEcsFields', ssh: Maybe<{ __typename?: 'SshEcsFields', signature: Maybe, method: Maybe }> }>, audit: Maybe<{ __typename?: 'AuditEcsFields', package: Maybe<{ __typename?: 'PackageEcsFields', arch: Maybe, entity_id: Maybe, name: Maybe, size: Maybe, summary: Maybe, version: Maybe }> }> }>, event: Maybe<{ __typename?: 'EventEcsFields', action: Maybe, category: Maybe, code: Maybe, created: Maybe, dataset: Maybe, duration: Maybe, end: Maybe, hash: Maybe, id: Maybe, kind: Maybe, module: Maybe, original: Maybe, outcome: Maybe, risk_score: Maybe, risk_score_norm: Maybe, severity: Maybe, start: Maybe, timezone: Maybe, type: Maybe }>, auditd: Maybe<{ __typename?: 'AuditdEcsFields', result: Maybe, session: Maybe, data: Maybe<{ __typename?: 'AuditdData', acct: Maybe, terminal: Maybe, op: Maybe }>, summary: Maybe<{ __typename?: 'Summary', how: Maybe, message_type: Maybe, sequence: Maybe, actor: Maybe<{ __typename?: 'PrimarySecondary', primary: Maybe, secondary: Maybe }>, object: Maybe<{ __typename?: 'PrimarySecondary', primary: Maybe, secondary: Maybe, type: Maybe }> }> }>, file: Maybe<{ __typename?: 'FileFields', name: Maybe, path: Maybe, target_path: Maybe, extension: Maybe, type: Maybe, device: Maybe, inode: Maybe, uid: Maybe, owner: Maybe, gid: Maybe, group: Maybe, mode: Maybe, size: Maybe, mtime: Maybe, ctime: Maybe }>, host: Maybe<{ __typename?: 'HostEcsFields', id: Maybe, name: Maybe, ip: Maybe }>, rule: Maybe<{ __typename?: 'RuleEcsField', reference: Maybe }>, source: Maybe<{ __typename?: 'SourceEcsFields', bytes: Maybe, ip: Maybe, packets: Maybe, port: Maybe, geo: Maybe<{ __typename?: 'GeoEcsFields', continent_name: Maybe, country_name: Maybe, country_iso_code: Maybe, city_name: Maybe, region_iso_code: Maybe, region_name: Maybe }> }>, destination: Maybe<{ __typename?: 'DestinationEcsFields', bytes: Maybe, ip: Maybe, packets: Maybe, port: Maybe, geo: Maybe<{ __typename?: 'GeoEcsFields', continent_name: Maybe, country_name: Maybe, country_iso_code: Maybe, city_name: Maybe, region_iso_code: Maybe, region_name: Maybe }> }>, dns: Maybe<{ __typename?: 'DnsEcsFields', resolved_ip: Maybe, response_code: Maybe, question: Maybe<{ __typename?: 'DnsQuestionData', name: Maybe, type: Maybe }> }>, endgame: Maybe<{ __typename?: 'EndgameEcsFields', exit_code: Maybe, file_name: Maybe, file_path: Maybe, logon_type: Maybe, parent_process_name: Maybe, pid: Maybe, process_name: Maybe, subject_domain_name: Maybe, subject_logon_id: Maybe, subject_user_name: Maybe, target_domain_name: Maybe, target_logon_id: Maybe, target_user_name: Maybe }>, geo: Maybe<{ __typename?: 'GeoEcsFields', region_name: Maybe, country_iso_code: Maybe }>, signal: Maybe<{ __typename?: 'SignalField', original_time: Maybe, rule: Maybe<{ __typename?: 'RuleField', id: Maybe, saved_id: Maybe, timeline_id: Maybe, timeline_title: Maybe, output_index: Maybe, from: Maybe, index: Maybe, language: Maybe, query: Maybe, to: Maybe, filters: Maybe }> }>, suricata: Maybe<{ __typename?: 'SuricataEcsFields', eve: Maybe<{ __typename?: 'SuricataEveData', proto: Maybe, flow_id: Maybe, alert: Maybe<{ __typename?: 'SuricataAlertData', signature: Maybe, signature_id: Maybe }> }> }>, network: Maybe<{ __typename?: 'NetworkEcsField', bytes: Maybe, community_id: Maybe, direction: Maybe, packets: Maybe, protocol: Maybe, transport: Maybe }>, http: Maybe<{ __typename?: 'HttpEcsFields', version: Maybe, request: Maybe<{ __typename?: 'HttpRequestData', method: Maybe, referrer: Maybe, body: Maybe<{ __typename?: 'HttpBodyData', bytes: Maybe, content: Maybe }> }>, response: Maybe<{ __typename?: 'HttpResponseData', status_code: Maybe, body: Maybe<{ __typename?: 'HttpBodyData', bytes: Maybe, content: Maybe }> }> }>, tls: Maybe<{ __typename?: 'TlsEcsFields', client_certificate: Maybe<{ __typename?: 'TlsClientCertificateData', fingerprint: Maybe<{ __typename?: 'FingerprintData', sha1: Maybe }> }>, fingerprints: Maybe<{ __typename?: 'TlsFingerprintsData', ja3: Maybe<{ __typename?: 'TlsJa3Data', hash: Maybe }> }>, server_certificate: Maybe<{ __typename?: 'TlsServerCertificateData', fingerprint: Maybe<{ __typename?: 'FingerprintData', sha1: Maybe }> }> }>, url: Maybe<{ __typename?: 'UrlEcsFields', original: Maybe, domain: Maybe, username: Maybe, password: Maybe }>, user: Maybe<{ __typename?: 'UserEcsFields', domain: Maybe, name: Maybe }>, winlog: Maybe<{ __typename?: 'WinlogEcsFields', event_id: Maybe }>, process: Maybe<{ __typename?: 'ProcessEcsFields', pid: Maybe, name: Maybe, ppid: Maybe, args: Maybe, executable: Maybe, title: Maybe, working_directory: Maybe, hash: Maybe<{ __typename?: 'ProcessHashData', md5: Maybe, sha1: Maybe, sha256: Maybe }> }>, zeek: Maybe<{ __typename?: 'ZeekEcsFields', session_id: Maybe, connection: Maybe<{ __typename?: 'ZeekConnectionData', local_resp: Maybe, local_orig: Maybe, missed_bytes: Maybe, state: Maybe, history: Maybe }>, notice: Maybe<{ __typename?: 'ZeekNoticeData', suppress_for: Maybe, msg: Maybe, note: Maybe, sub: Maybe, dst: Maybe, dropped: Maybe, peer_descr: Maybe }>, dns: Maybe<{ __typename?: 'ZeekDnsData', AA: Maybe, qclass_name: Maybe, RD: Maybe, qtype_name: Maybe, rejected: Maybe, qtype: Maybe, query: Maybe, trans_id: Maybe, qclass: Maybe, RA: Maybe, TC: Maybe }>, http: Maybe<{ __typename?: 'ZeekHttpData', resp_mime_types: Maybe, trans_depth: Maybe, status_msg: Maybe, resp_fuids: Maybe, tags: Maybe }>, files: Maybe<{ __typename?: 'ZeekFileData', session_ids: Maybe, timedout: Maybe, local_orig: Maybe, tx_host: Maybe, source: Maybe, is_orig: Maybe, overflow_bytes: Maybe, sha1: Maybe, duration: Maybe, depth: Maybe, analyzers: Maybe, mime_type: Maybe, rx_host: Maybe, total_bytes: Maybe, fuid: Maybe, seen_bytes: Maybe, missing_bytes: Maybe, md5: Maybe }>, ssl: Maybe<{ __typename?: 'ZeekSslData', cipher: Maybe, established: Maybe, resumed: Maybe, version: Maybe }> }> } } }> } } }; + +export type PersistTimelineNoteMutationMutationVariables = { + noteId?: Maybe, + version?: Maybe, + note: NoteInput +}; + + +export type PersistTimelineNoteMutationMutation = { __typename?: 'Mutation', persistNote: { __typename?: 'ResponseNote', code: Maybe, message: Maybe, note: { __typename?: 'NoteResult', eventId: Maybe, note: Maybe, timelineId: Maybe, timelineVersion: Maybe, noteId: string, created: Maybe, createdBy: Maybe, updated: Maybe, updatedBy: Maybe, version: Maybe } } }; + +export type GetOneTimelineQueryVariables = { + id: Scalars['ID'] +}; + + +export type GetOneTimelineQuery = { __typename?: 'Query', getOneTimeline: { __typename?: 'TimelineResult', savedObjectId: string, description: Maybe, eventType: Maybe, kqlMode: Maybe, noteIds: Maybe>, pinnedEventIds: Maybe>, title: Maybe, savedQueryId: Maybe, created: Maybe, createdBy: Maybe, updated: Maybe, updatedBy: Maybe, version: string, columns: Maybe, category: Maybe, columnHeaderType: Maybe, description: Maybe, example: Maybe, indexes: Maybe>, id: Maybe, name: Maybe, searchable: Maybe, type: Maybe }>>, dataProviders: Maybe, name: Maybe, enabled: Maybe, excluded: Maybe, kqlQuery: Maybe, queryMatch: Maybe<{ __typename?: 'QueryMatchResult', field: Maybe, displayField: Maybe, value: Maybe, displayValue: Maybe, operator: Maybe }>, and: Maybe, name: Maybe, enabled: Maybe, excluded: Maybe, kqlQuery: Maybe, queryMatch: Maybe<{ __typename?: 'QueryMatchResult', field: Maybe, displayField: Maybe, value: Maybe, displayValue: Maybe, operator: Maybe }> }>> }>>, dateRange: Maybe<{ __typename?: 'DateRangePickerResult', start: Maybe, end: Maybe }>, eventIdToNoteIds: Maybe, note: Maybe, timelineId: Maybe, noteId: string, created: Maybe, createdBy: Maybe, timelineVersion: Maybe, updated: Maybe, updatedBy: Maybe, version: Maybe }>>, favorite: Maybe, userName: Maybe, favoriteDate: Maybe }>>, filters: Maybe, exists: Maybe, match_all: Maybe, missing: Maybe, range: Maybe, script: Maybe, meta: Maybe<{ __typename?: 'FilterMetaTimelineResult', alias: Maybe, controlledBy: Maybe, disabled: Maybe, field: Maybe, formattedValue: Maybe, index: Maybe, key: Maybe, negate: Maybe, params: Maybe, type: Maybe, value: Maybe }> }>>, kqlQuery: Maybe<{ __typename?: 'SerializedFilterQueryResult', filterQuery: Maybe<{ __typename?: 'SerializedKueryQueryResult', serializedQuery: Maybe, kuery: Maybe<{ __typename?: 'KueryFilterQueryResult', kind: Maybe, expression: Maybe }> }> }>, notes: Maybe, note: Maybe, timelineId: Maybe, timelineVersion: Maybe, noteId: string, created: Maybe, createdBy: Maybe, updated: Maybe, updatedBy: Maybe, version: Maybe }>>, pinnedEventsSaveObject: Maybe, timelineId: Maybe, created: Maybe, createdBy: Maybe, updated: Maybe, updatedBy: Maybe, version: Maybe }>>, sort: Maybe<{ __typename?: 'SortTimelineResult', columnId: Maybe, sortDirection: Maybe }> } }; + +export type PersistTimelineMutationMutationVariables = { + timelineId?: Maybe, + version?: Maybe, + timeline: TimelineInput +}; + + +export type PersistTimelineMutationMutation = { __typename?: 'Mutation', persistTimeline: { __typename?: 'ResponseTimeline', code: Maybe, message: Maybe, timeline: { __typename?: 'TimelineResult', savedObjectId: string, version: string, description: Maybe, eventType: Maybe, kqlMode: Maybe, title: Maybe, savedQueryId: Maybe, created: Maybe, createdBy: Maybe, updated: Maybe, updatedBy: Maybe, columns: Maybe, category: Maybe, columnHeaderType: Maybe, description: Maybe, example: Maybe, indexes: Maybe>, id: Maybe, name: Maybe, searchable: Maybe, type: Maybe }>>, dataProviders: Maybe, name: Maybe, enabled: Maybe, excluded: Maybe, kqlQuery: Maybe, queryMatch: Maybe<{ __typename?: 'QueryMatchResult', field: Maybe, displayField: Maybe, value: Maybe, displayValue: Maybe, operator: Maybe }>, and: Maybe, name: Maybe, enabled: Maybe, excluded: Maybe, kqlQuery: Maybe, queryMatch: Maybe<{ __typename?: 'QueryMatchResult', field: Maybe, displayField: Maybe, value: Maybe, displayValue: Maybe, operator: Maybe }> }>> }>>, favorite: Maybe, userName: Maybe, favoriteDate: Maybe }>>, filters: Maybe, exists: Maybe, match_all: Maybe, missing: Maybe, range: Maybe, script: Maybe, meta: Maybe<{ __typename?: 'FilterMetaTimelineResult', alias: Maybe, controlledBy: Maybe, disabled: Maybe, field: Maybe, formattedValue: Maybe, index: Maybe, key: Maybe, negate: Maybe, params: Maybe, type: Maybe, value: Maybe }> }>>, kqlQuery: Maybe<{ __typename?: 'SerializedFilterQueryResult', filterQuery: Maybe<{ __typename?: 'SerializedKueryQueryResult', serializedQuery: Maybe, kuery: Maybe<{ __typename?: 'KueryFilterQueryResult', kind: Maybe, expression: Maybe }> }> }>, dateRange: Maybe<{ __typename?: 'DateRangePickerResult', start: Maybe, end: Maybe }>, sort: Maybe<{ __typename?: 'SortTimelineResult', columnId: Maybe, sortDirection: Maybe }> } } }; + +export type PersistTimelinePinnedEventMutationMutationVariables = { + pinnedEventId?: Maybe, + eventId: Scalars['ID'], + timelineId?: Maybe +}; + + +export type PersistTimelinePinnedEventMutationMutation = { __typename?: 'Mutation', persistPinnedEventOnTimeline: Maybe<{ __typename?: 'PinnedEvent', pinnedEventId: string, eventId: Maybe, timelineId: Maybe, timelineVersion: Maybe, created: Maybe, createdBy: Maybe, updated: Maybe, updatedBy: Maybe, version: Maybe }> }; + +export type GetTlsQueryQueryVariables = { + sourceId: Scalars['ID'], + filterQuery?: Maybe, + flowTarget: FlowTargetSourceDest, + ip: Scalars['String'], + pagination: PaginationInputPaginated, + sort: TlsSortField, + timerange: TimerangeInput, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetTlsQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, Tls: { __typename?: 'TlsData', totalCount: number, edges: Array<{ __typename?: 'TlsEdges', node: { __typename?: 'TlsNode', _id: Maybe, alternativeNames: Maybe>, commonNames: Maybe>, ja3: Maybe>, issuerNames: Maybe>, notAfter: Maybe> }, cursor: { __typename?: 'CursorType', value: Maybe } }>, pageInfo: { __typename?: 'PageInfoPaginated', activePage: number, fakeTotalCount: number, showMorePagesIndicator: boolean }, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export type GetUncommonProcessesQueryQueryVariables = { + sourceId: Scalars['ID'], + timerange: TimerangeInput, + pagination: PaginationInputPaginated, + filterQuery?: Maybe, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetUncommonProcessesQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, UncommonProcesses: { __typename?: 'UncommonProcessesData', totalCount: number, edges: Array<{ __typename?: 'UncommonProcessesEdges', node: { __typename?: 'UncommonProcessItem', _id: string, instances: number, process: { __typename?: 'ProcessEcsFields', args: Maybe, name: Maybe }, user: Maybe<{ __typename?: 'UserEcsFields', id: Maybe, name: Maybe }>, hosts: Array<{ __typename?: 'HostEcsFields', name: Maybe }> }, cursor: { __typename?: 'CursorType', value: Maybe } }>, pageInfo: { __typename?: 'PageInfoPaginated', activePage: number, fakeTotalCount: number, showMorePagesIndicator: boolean }, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export type GetUsersQueryQueryVariables = { + sourceId: Scalars['ID'], + filterQuery?: Maybe, + flowTarget: FlowTarget, + ip: Scalars['String'], + pagination: PaginationInputPaginated, + sort: UsersSortField, + timerange: TimerangeInput, + defaultIndex: Array, + inspect: Scalars['Boolean'] +}; + + +export type GetUsersQueryQuery = { __typename?: 'Query', source: { __typename?: 'Source', id: string, Users: { __typename?: 'UsersData', totalCount: number, edges: Array<{ __typename?: 'UsersEdges', node: { __typename?: 'UsersNode', user: Maybe<{ __typename?: 'UsersItem', name: Maybe, id: Maybe, groupId: Maybe, groupName: Maybe, count: Maybe }> }, cursor: { __typename?: 'CursorType', value: Maybe } }>, pageInfo: { __typename?: 'PageInfoPaginated', activePage: number, fakeTotalCount: number, showMorePagesIndicator: boolean }, inspect: Maybe<{ __typename?: 'Inspect', dsl: Array, response: Array }> } } }; + +export const KpiHostDetailsChartFieldsFragmentDoc = gql` + fragment KpiHostDetailsChartFields on KpiHostHistogramData { + x + y +} + `; +export const KpiHostChartFieldsFragmentDoc = gql` + fragment KpiHostChartFields on KpiHostHistogramData { + x + y +} + `; +export const KpiNetworkChartFieldsFragmentDoc = gql` + fragment KpiNetworkChartFields on KpiNetworkHistogramData { + x + y +} + `; +export const GetAuthenticationsQueryDocument = gql` + query GetAuthenticationsQuery($sourceId: ID!, $timerange: TimerangeInput!, $pagination: PaginationInputPaginated!, $filterQuery: String, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + Authentications(timerange: $timerange, pagination: $pagination, filterQuery: $filterQuery, defaultIndex: $defaultIndex) { + totalCount + edges { + node { + _id + failures + successes + user { + name + } + lastSuccess { + timestamp + source { + ip + } + host { + id + name + } + } + lastFailure { + timestamp + source { + ip + } + host { + id + name + } + } + } + cursor { + value + } + } + pageInfo { + activePage + fakeTotalCount + showMorePagesIndicator + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetAuthenticationsQueryComponentProps = Omit, 'query'> & ({ variables: GetAuthenticationsQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetAuthenticationsQueryComponent = (props: GetAuthenticationsQueryComponentProps) => ( + query={GetAuthenticationsQueryDocument} {...props} /> + ); + + +/** + * __useGetAuthenticationsQueryQuery__ + * + * To run a query within a React component, call `useGetAuthenticationsQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetAuthenticationsQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetAuthenticationsQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * timerange: // value for 'timerange' + * pagination: // value for 'pagination' + * filterQuery: // value for 'filterQuery' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetAuthenticationsQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetAuthenticationsQueryDocument, baseOptions); + } +export function useGetAuthenticationsQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetAuthenticationsQueryDocument, baseOptions); + } +export type GetAuthenticationsQueryQueryHookResult = ReturnType; +export type GetAuthenticationsQueryLazyQueryHookResult = ReturnType; +export type GetAuthenticationsQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetLastEventTimeQueryDocument = gql` + query GetLastEventTimeQuery($sourceId: ID!, $indexKey: LastEventIndexKey!, $details: LastTimeDetails!, $defaultIndex: [String!]!) { + source(id: $sourceId) { + id + LastEventTime(indexKey: $indexKey, details: $details, defaultIndex: $defaultIndex) { + lastSeen + } + } +} + `; +export type GetLastEventTimeQueryComponentProps = Omit, 'query'> & ({ variables: GetLastEventTimeQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetLastEventTimeQueryComponent = (props: GetLastEventTimeQueryComponentProps) => ( + query={GetLastEventTimeQueryDocument} {...props} /> + ); + + +/** + * __useGetLastEventTimeQueryQuery__ + * + * To run a query within a React component, call `useGetLastEventTimeQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetLastEventTimeQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetLastEventTimeQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * indexKey: // value for 'indexKey' + * details: // value for 'details' + * defaultIndex: // value for 'defaultIndex' + * }, + * }); + */ +export function useGetLastEventTimeQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetLastEventTimeQueryDocument, baseOptions); + } +export function useGetLastEventTimeQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetLastEventTimeQueryDocument, baseOptions); + } +export type GetLastEventTimeQueryQueryHookResult = ReturnType; +export type GetLastEventTimeQueryLazyQueryHookResult = ReturnType; +export type GetLastEventTimeQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetHostFirstLastSeenQueryDocument = gql` + query GetHostFirstLastSeenQuery($sourceId: ID!, $hostName: String!, $defaultIndex: [String!]!) { + source(id: $sourceId) { + id + HostFirstLastSeen(hostName: $hostName, defaultIndex: $defaultIndex) { + firstSeen + lastSeen + } + } +} + `; +export type GetHostFirstLastSeenQueryComponentProps = Omit, 'query'> & ({ variables: GetHostFirstLastSeenQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetHostFirstLastSeenQueryComponent = (props: GetHostFirstLastSeenQueryComponentProps) => ( + query={GetHostFirstLastSeenQueryDocument} {...props} /> + ); + + +/** + * __useGetHostFirstLastSeenQueryQuery__ + * + * To run a query within a React component, call `useGetHostFirstLastSeenQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetHostFirstLastSeenQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetHostFirstLastSeenQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * hostName: // value for 'hostName' + * defaultIndex: // value for 'defaultIndex' + * }, + * }); + */ +export function useGetHostFirstLastSeenQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetHostFirstLastSeenQueryDocument, baseOptions); + } +export function useGetHostFirstLastSeenQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetHostFirstLastSeenQueryDocument, baseOptions); + } +export type GetHostFirstLastSeenQueryQueryHookResult = ReturnType; +export type GetHostFirstLastSeenQueryLazyQueryHookResult = ReturnType; +export type GetHostFirstLastSeenQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetHostsTableQueryDocument = gql` + query GetHostsTableQuery($sourceId: ID!, $timerange: TimerangeInput!, $pagination: PaginationInputPaginated!, $sort: HostsSortField!, $filterQuery: String, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + Hosts(timerange: $timerange, pagination: $pagination, sort: $sort, filterQuery: $filterQuery, defaultIndex: $defaultIndex) { + totalCount + edges { + node { + _id + lastSeen + host { + id + name + os { + name + version + } + } + } + cursor { + value + } + } + pageInfo { + activePage + fakeTotalCount + showMorePagesIndicator + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetHostsTableQueryComponentProps = Omit, 'query'> & ({ variables: GetHostsTableQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetHostsTableQueryComponent = (props: GetHostsTableQueryComponentProps) => ( + query={GetHostsTableQueryDocument} {...props} /> + ); + + +/** + * __useGetHostsTableQueryQuery__ + * + * To run a query within a React component, call `useGetHostsTableQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetHostsTableQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetHostsTableQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * timerange: // value for 'timerange' + * pagination: // value for 'pagination' + * sort: // value for 'sort' + * filterQuery: // value for 'filterQuery' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetHostsTableQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetHostsTableQueryDocument, baseOptions); + } +export function useGetHostsTableQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetHostsTableQueryDocument, baseOptions); + } +export type GetHostsTableQueryQueryHookResult = ReturnType; +export type GetHostsTableQueryLazyQueryHookResult = ReturnType; +export type GetHostsTableQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetHostOverviewQueryDocument = gql` + query GetHostOverviewQuery($sourceId: ID!, $hostName: String!, $timerange: TimerangeInput!, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + HostOverview(hostName: $hostName, timerange: $timerange, defaultIndex: $defaultIndex) { + _id + host { + architecture + id + ip + mac + name + os { + family + name + platform + version + } + type + } + cloud { + instance { + id + } + machine { + type + } + provider + region + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetHostOverviewQueryComponentProps = Omit, 'query'> & ({ variables: GetHostOverviewQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetHostOverviewQueryComponent = (props: GetHostOverviewQueryComponentProps) => ( + query={GetHostOverviewQueryDocument} {...props} /> + ); + + +/** + * __useGetHostOverviewQueryQuery__ + * + * To run a query within a React component, call `useGetHostOverviewQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetHostOverviewQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetHostOverviewQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * hostName: // value for 'hostName' + * timerange: // value for 'timerange' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetHostOverviewQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetHostOverviewQueryDocument, baseOptions); + } +export function useGetHostOverviewQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetHostOverviewQueryDocument, baseOptions); + } +export type GetHostOverviewQueryQueryHookResult = ReturnType; +export type GetHostOverviewQueryLazyQueryHookResult = ReturnType; +export type GetHostOverviewQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetIpOverviewQueryDocument = gql` + query GetIpOverviewQuery($sourceId: ID!, $filterQuery: String, $ip: String!, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + IpOverview(filterQuery: $filterQuery, ip: $ip, defaultIndex: $defaultIndex) { + source { + firstSeen + lastSeen + autonomousSystem { + number + organization { + name + } + } + geo { + continent_name + city_name + country_iso_code + country_name + location { + lat + lon + } + region_iso_code + region_name + } + } + destination { + firstSeen + lastSeen + autonomousSystem { + number + organization { + name + } + } + geo { + continent_name + city_name + country_iso_code + country_name + location { + lat + lon + } + region_iso_code + region_name + } + } + host { + architecture + id + ip + mac + name + os { + family + name + platform + version + } + type + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetIpOverviewQueryComponentProps = Omit, 'query'> & ({ variables: GetIpOverviewQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetIpOverviewQueryComponent = (props: GetIpOverviewQueryComponentProps) => ( + query={GetIpOverviewQueryDocument} {...props} /> + ); + + +/** + * __useGetIpOverviewQueryQuery__ + * + * To run a query within a React component, call `useGetIpOverviewQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetIpOverviewQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetIpOverviewQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * filterQuery: // value for 'filterQuery' + * ip: // value for 'ip' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetIpOverviewQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetIpOverviewQueryDocument, baseOptions); + } +export function useGetIpOverviewQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetIpOverviewQueryDocument, baseOptions); + } +export type GetIpOverviewQueryQueryHookResult = ReturnType; +export type GetIpOverviewQueryLazyQueryHookResult = ReturnType; +export type GetIpOverviewQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetKpiHostDetailsQueryDocument = gql` + query GetKpiHostDetailsQuery($sourceId: ID!, $timerange: TimerangeInput!, $filterQuery: String, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + KpiHostDetails(timerange: $timerange, filterQuery: $filterQuery, defaultIndex: $defaultIndex) { + authSuccess + authSuccessHistogram { + ...KpiHostDetailsChartFields + } + authFailure + authFailureHistogram { + ...KpiHostDetailsChartFields + } + uniqueSourceIps + uniqueSourceIpsHistogram { + ...KpiHostDetailsChartFields + } + uniqueDestinationIps + uniqueDestinationIpsHistogram { + ...KpiHostDetailsChartFields + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + ${KpiHostDetailsChartFieldsFragmentDoc}`; +export type GetKpiHostDetailsQueryComponentProps = Omit, 'query'> & ({ variables: GetKpiHostDetailsQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetKpiHostDetailsQueryComponent = (props: GetKpiHostDetailsQueryComponentProps) => ( + query={GetKpiHostDetailsQueryDocument} {...props} /> + ); + + +/** + * __useGetKpiHostDetailsQueryQuery__ + * + * To run a query within a React component, call `useGetKpiHostDetailsQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetKpiHostDetailsQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetKpiHostDetailsQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * timerange: // value for 'timerange' + * filterQuery: // value for 'filterQuery' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetKpiHostDetailsQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetKpiHostDetailsQueryDocument, baseOptions); + } +export function useGetKpiHostDetailsQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetKpiHostDetailsQueryDocument, baseOptions); + } +export type GetKpiHostDetailsQueryQueryHookResult = ReturnType; +export type GetKpiHostDetailsQueryLazyQueryHookResult = ReturnType; +export type GetKpiHostDetailsQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetKpiHostsQueryDocument = gql` + query GetKpiHostsQuery($sourceId: ID!, $timerange: TimerangeInput!, $filterQuery: String, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + KpiHosts(timerange: $timerange, filterQuery: $filterQuery, defaultIndex: $defaultIndex) { + hosts + hostsHistogram { + ...KpiHostChartFields + } + authSuccess + authSuccessHistogram { + ...KpiHostChartFields + } + authFailure + authFailureHistogram { + ...KpiHostChartFields + } + uniqueSourceIps + uniqueSourceIpsHistogram { + ...KpiHostChartFields + } + uniqueDestinationIps + uniqueDestinationIpsHistogram { + ...KpiHostChartFields + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + ${KpiHostChartFieldsFragmentDoc}`; +export type GetKpiHostsQueryComponentProps = Omit, 'query'> & ({ variables: GetKpiHostsQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetKpiHostsQueryComponent = (props: GetKpiHostsQueryComponentProps) => ( + query={GetKpiHostsQueryDocument} {...props} /> + ); + + +/** + * __useGetKpiHostsQueryQuery__ + * + * To run a query within a React component, call `useGetKpiHostsQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetKpiHostsQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetKpiHostsQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * timerange: // value for 'timerange' + * filterQuery: // value for 'filterQuery' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetKpiHostsQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetKpiHostsQueryDocument, baseOptions); + } +export function useGetKpiHostsQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetKpiHostsQueryDocument, baseOptions); + } +export type GetKpiHostsQueryQueryHookResult = ReturnType; +export type GetKpiHostsQueryLazyQueryHookResult = ReturnType; +export type GetKpiHostsQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetKpiNetworkQueryDocument = gql` + query GetKpiNetworkQuery($sourceId: ID!, $timerange: TimerangeInput!, $filterQuery: String, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + KpiNetwork(timerange: $timerange, filterQuery: $filterQuery, defaultIndex: $defaultIndex) { + networkEvents + uniqueFlowId + uniqueSourcePrivateIps + uniqueSourcePrivateIpsHistogram { + ...KpiNetworkChartFields + } + uniqueDestinationPrivateIps + uniqueDestinationPrivateIpsHistogram { + ...KpiNetworkChartFields + } + dnsQueries + tlsHandshakes + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + ${KpiNetworkChartFieldsFragmentDoc}`; +export type GetKpiNetworkQueryComponentProps = Omit, 'query'> & ({ variables: GetKpiNetworkQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetKpiNetworkQueryComponent = (props: GetKpiNetworkQueryComponentProps) => ( + query={GetKpiNetworkQueryDocument} {...props} /> + ); + + +/** + * __useGetKpiNetworkQueryQuery__ + * + * To run a query within a React component, call `useGetKpiNetworkQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetKpiNetworkQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetKpiNetworkQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * timerange: // value for 'timerange' + * filterQuery: // value for 'filterQuery' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetKpiNetworkQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetKpiNetworkQueryDocument, baseOptions); + } +export function useGetKpiNetworkQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetKpiNetworkQueryDocument, baseOptions); + } +export type GetKpiNetworkQueryQueryHookResult = ReturnType; +export type GetKpiNetworkQueryLazyQueryHookResult = ReturnType; +export type GetKpiNetworkQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetMatrixHistogramQueryDocument = gql` + query GetMatrixHistogramQuery($defaultIndex: [String!]!, $filterQuery: String, $histogramType: HistogramType!, $inspect: Boolean!, $sourceId: ID!, $stackByField: String!, $timerange: TimerangeInput!) { + source(id: $sourceId) { + id + MatrixHistogram(timerange: $timerange, filterQuery: $filterQuery, defaultIndex: $defaultIndex, stackByField: $stackByField, histogramType: $histogramType) { + matrixHistogramData { + x + y + g + } + totalCount + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetMatrixHistogramQueryComponentProps = Omit, 'query'> & ({ variables: GetMatrixHistogramQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetMatrixHistogramQueryComponent = (props: GetMatrixHistogramQueryComponentProps) => ( + query={GetMatrixHistogramQueryDocument} {...props} /> + ); + + +/** + * __useGetMatrixHistogramQueryQuery__ + * + * To run a query within a React component, call `useGetMatrixHistogramQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetMatrixHistogramQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetMatrixHistogramQueryQuery({ + * variables: { + * defaultIndex: // value for 'defaultIndex' + * filterQuery: // value for 'filterQuery' + * histogramType: // value for 'histogramType' + * inspect: // value for 'inspect' + * sourceId: // value for 'sourceId' + * stackByField: // value for 'stackByField' + * timerange: // value for 'timerange' + * }, + * }); + */ +export function useGetMatrixHistogramQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetMatrixHistogramQueryDocument, baseOptions); + } +export function useGetMatrixHistogramQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetMatrixHistogramQueryDocument, baseOptions); + } +export type GetMatrixHistogramQueryQueryHookResult = ReturnType; +export type GetMatrixHistogramQueryLazyQueryHookResult = ReturnType; +export type GetMatrixHistogramQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetNetworkDnsQueryDocument = gql` + query GetNetworkDnsQuery($defaultIndex: [String!]!, $filterQuery: String, $inspect: Boolean!, $isPtrIncluded: Boolean!, $pagination: PaginationInputPaginated!, $sort: NetworkDnsSortField!, $sourceId: ID!, $stackByField: String, $timerange: TimerangeInput!) { + source(id: $sourceId) { + id + NetworkDns(isPtrIncluded: $isPtrIncluded, sort: $sort, timerange: $timerange, pagination: $pagination, filterQuery: $filterQuery, defaultIndex: $defaultIndex, stackByField: $stackByField) { + totalCount + edges { + node { + _id + dnsBytesIn + dnsBytesOut + dnsName + queryCount + uniqueDomains + } + cursor { + value + } + } + pageInfo { + activePage + fakeTotalCount + showMorePagesIndicator + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetNetworkDnsQueryComponentProps = Omit, 'query'> & ({ variables: GetNetworkDnsQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetNetworkDnsQueryComponent = (props: GetNetworkDnsQueryComponentProps) => ( + query={GetNetworkDnsQueryDocument} {...props} /> + ); + + +/** + * __useGetNetworkDnsQueryQuery__ + * + * To run a query within a React component, call `useGetNetworkDnsQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetNetworkDnsQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetNetworkDnsQueryQuery({ + * variables: { + * defaultIndex: // value for 'defaultIndex' + * filterQuery: // value for 'filterQuery' + * inspect: // value for 'inspect' + * isPtrIncluded: // value for 'isPtrIncluded' + * pagination: // value for 'pagination' + * sort: // value for 'sort' + * sourceId: // value for 'sourceId' + * stackByField: // value for 'stackByField' + * timerange: // value for 'timerange' + * }, + * }); + */ +export function useGetNetworkDnsQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetNetworkDnsQueryDocument, baseOptions); + } +export function useGetNetworkDnsQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetNetworkDnsQueryDocument, baseOptions); + } +export type GetNetworkDnsQueryQueryHookResult = ReturnType; +export type GetNetworkDnsQueryLazyQueryHookResult = ReturnType; +export type GetNetworkDnsQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetNetworkHttpQueryDocument = gql` + query GetNetworkHttpQuery($sourceId: ID!, $ip: String, $filterQuery: String, $pagination: PaginationInputPaginated!, $sort: NetworkHttpSortField!, $timerange: TimerangeInput!, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + NetworkHttp(filterQuery: $filterQuery, ip: $ip, pagination: $pagination, sort: $sort, timerange: $timerange, defaultIndex: $defaultIndex) { + totalCount + edges { + node { + domains + lastHost + lastSourceIp + methods + path + requestCount + statuses + } + cursor { + value + } + } + pageInfo { + activePage + fakeTotalCount + showMorePagesIndicator + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetNetworkHttpQueryComponentProps = Omit, 'query'> & ({ variables: GetNetworkHttpQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetNetworkHttpQueryComponent = (props: GetNetworkHttpQueryComponentProps) => ( + query={GetNetworkHttpQueryDocument} {...props} /> + ); + + +/** + * __useGetNetworkHttpQueryQuery__ + * + * To run a query within a React component, call `useGetNetworkHttpQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetNetworkHttpQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetNetworkHttpQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * ip: // value for 'ip' + * filterQuery: // value for 'filterQuery' + * pagination: // value for 'pagination' + * sort: // value for 'sort' + * timerange: // value for 'timerange' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetNetworkHttpQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetNetworkHttpQueryDocument, baseOptions); + } +export function useGetNetworkHttpQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetNetworkHttpQueryDocument, baseOptions); + } +export type GetNetworkHttpQueryQueryHookResult = ReturnType; +export type GetNetworkHttpQueryLazyQueryHookResult = ReturnType; +export type GetNetworkHttpQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetNetworkTopCountriesQueryDocument = gql` + query GetNetworkTopCountriesQuery($sourceId: ID!, $ip: String, $filterQuery: String, $pagination: PaginationInputPaginated!, $sort: NetworkTopTablesSortField!, $flowTarget: FlowTargetSourceDest!, $timerange: TimerangeInput!, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + NetworkTopCountries(filterQuery: $filterQuery, flowTarget: $flowTarget, ip: $ip, pagination: $pagination, sort: $sort, timerange: $timerange, defaultIndex: $defaultIndex) { + totalCount + edges { + node { + source { + country + destination_ips + flows + source_ips + } + destination { + country + destination_ips + flows + source_ips + } + network { + bytes_in + bytes_out + } + } + cursor { + value + } + } + pageInfo { + activePage + fakeTotalCount + showMorePagesIndicator + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetNetworkTopCountriesQueryComponentProps = Omit, 'query'> & ({ variables: GetNetworkTopCountriesQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetNetworkTopCountriesQueryComponent = (props: GetNetworkTopCountriesQueryComponentProps) => ( + query={GetNetworkTopCountriesQueryDocument} {...props} /> + ); + + +/** + * __useGetNetworkTopCountriesQueryQuery__ + * + * To run a query within a React component, call `useGetNetworkTopCountriesQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetNetworkTopCountriesQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetNetworkTopCountriesQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * ip: // value for 'ip' + * filterQuery: // value for 'filterQuery' + * pagination: // value for 'pagination' + * sort: // value for 'sort' + * flowTarget: // value for 'flowTarget' + * timerange: // value for 'timerange' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetNetworkTopCountriesQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetNetworkTopCountriesQueryDocument, baseOptions); + } +export function useGetNetworkTopCountriesQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetNetworkTopCountriesQueryDocument, baseOptions); + } +export type GetNetworkTopCountriesQueryQueryHookResult = ReturnType; +export type GetNetworkTopCountriesQueryLazyQueryHookResult = ReturnType; +export type GetNetworkTopCountriesQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetNetworkTopNFlowQueryDocument = gql` + query GetNetworkTopNFlowQuery($sourceId: ID!, $ip: String, $filterQuery: String, $pagination: PaginationInputPaginated!, $sort: NetworkTopTablesSortField!, $flowTarget: FlowTargetSourceDest!, $timerange: TimerangeInput!, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + NetworkTopNFlow(filterQuery: $filterQuery, flowTarget: $flowTarget, ip: $ip, pagination: $pagination, sort: $sort, timerange: $timerange, defaultIndex: $defaultIndex) { + totalCount + edges { + node { + source { + autonomous_system { + name + number + } + domain + ip + location { + geo { + continent_name + country_name + country_iso_code + city_name + region_iso_code + region_name + } + flowTarget + } + flows + destination_ips + } + destination { + autonomous_system { + name + number + } + domain + ip + location { + geo { + continent_name + country_name + country_iso_code + city_name + region_iso_code + region_name + } + flowTarget + } + flows + source_ips + } + network { + bytes_in + bytes_out + } + } + cursor { + value + } + } + pageInfo { + activePage + fakeTotalCount + showMorePagesIndicator + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetNetworkTopNFlowQueryComponentProps = Omit, 'query'> & ({ variables: GetNetworkTopNFlowQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetNetworkTopNFlowQueryComponent = (props: GetNetworkTopNFlowQueryComponentProps) => ( + query={GetNetworkTopNFlowQueryDocument} {...props} /> + ); + + +/** + * __useGetNetworkTopNFlowQueryQuery__ + * + * To run a query within a React component, call `useGetNetworkTopNFlowQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetNetworkTopNFlowQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetNetworkTopNFlowQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * ip: // value for 'ip' + * filterQuery: // value for 'filterQuery' + * pagination: // value for 'pagination' + * sort: // value for 'sort' + * flowTarget: // value for 'flowTarget' + * timerange: // value for 'timerange' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetNetworkTopNFlowQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetNetworkTopNFlowQueryDocument, baseOptions); + } +export function useGetNetworkTopNFlowQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetNetworkTopNFlowQueryDocument, baseOptions); + } +export type GetNetworkTopNFlowQueryQueryHookResult = ReturnType; +export type GetNetworkTopNFlowQueryLazyQueryHookResult = ReturnType; +export type GetNetworkTopNFlowQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetOverviewHostQueryDocument = gql` + query GetOverviewHostQuery($sourceId: ID!, $timerange: TimerangeInput!, $filterQuery: String, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + OverviewHost(timerange: $timerange, filterQuery: $filterQuery, defaultIndex: $defaultIndex) { + auditbeatAuditd + auditbeatFIM + auditbeatLogin + auditbeatPackage + auditbeatProcess + auditbeatUser + endgameDns + endgameFile + endgameImageLoad + endgameNetwork + endgameProcess + endgameRegistry + endgameSecurity + filebeatSystemModule + winlogbeatSecurity + winlogbeatMWSysmonOperational + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetOverviewHostQueryComponentProps = Omit, 'query'> & ({ variables: GetOverviewHostQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetOverviewHostQueryComponent = (props: GetOverviewHostQueryComponentProps) => ( + query={GetOverviewHostQueryDocument} {...props} /> + ); + + +/** + * __useGetOverviewHostQueryQuery__ + * + * To run a query within a React component, call `useGetOverviewHostQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetOverviewHostQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetOverviewHostQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * timerange: // value for 'timerange' + * filterQuery: // value for 'filterQuery' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetOverviewHostQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetOverviewHostQueryDocument, baseOptions); + } +export function useGetOverviewHostQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetOverviewHostQueryDocument, baseOptions); + } +export type GetOverviewHostQueryQueryHookResult = ReturnType; +export type GetOverviewHostQueryLazyQueryHookResult = ReturnType; +export type GetOverviewHostQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetOverviewNetworkQueryDocument = gql` + query GetOverviewNetworkQuery($sourceId: ID!, $timerange: TimerangeInput!, $filterQuery: String, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + OverviewNetwork(timerange: $timerange, filterQuery: $filterQuery, defaultIndex: $defaultIndex) { + auditbeatSocket + filebeatCisco + filebeatNetflow + filebeatPanw + filebeatSuricata + filebeatZeek + packetbeatDNS + packetbeatFlow + packetbeatTLS + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetOverviewNetworkQueryComponentProps = Omit, 'query'> & ({ variables: GetOverviewNetworkQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetOverviewNetworkQueryComponent = (props: GetOverviewNetworkQueryComponentProps) => ( + query={GetOverviewNetworkQueryDocument} {...props} /> + ); + + +/** + * __useGetOverviewNetworkQueryQuery__ + * + * To run a query within a React component, call `useGetOverviewNetworkQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetOverviewNetworkQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetOverviewNetworkQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * timerange: // value for 'timerange' + * filterQuery: // value for 'filterQuery' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetOverviewNetworkQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetOverviewNetworkQueryDocument, baseOptions); + } +export function useGetOverviewNetworkQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetOverviewNetworkQueryDocument, baseOptions); + } +export type GetOverviewNetworkQueryQueryHookResult = ReturnType; +export type GetOverviewNetworkQueryLazyQueryHookResult = ReturnType; +export type GetOverviewNetworkQueryQueryResult = ApolloReactCommon.QueryResult; +export const SourceQueryDocument = gql` + query SourceQuery($sourceId: ID = "default", $defaultIndex: [String!]!) { + source(id: $sourceId) { + id + status { + indicesExist(defaultIndex: $defaultIndex) + indexFields(defaultIndex: $defaultIndex) { + category + description + example + indexes + name + searchable + type + aggregatable + format + } + } + } +} + `; +export type SourceQueryComponentProps = Omit, 'query'> & ({ variables: SourceQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const SourceQueryComponent = (props: SourceQueryComponentProps) => ( + query={SourceQueryDocument} {...props} /> + ); + + +/** + * __useSourceQueryQuery__ + * + * To run a query within a React component, call `useSourceQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useSourceQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useSourceQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * defaultIndex: // value for 'defaultIndex' + * }, + * }); + */ +export function useSourceQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(SourceQueryDocument, baseOptions); + } +export function useSourceQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(SourceQueryDocument, baseOptions); + } +export type SourceQueryQueryHookResult = ReturnType; +export type SourceQueryLazyQueryHookResult = ReturnType; +export type SourceQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetAllTimelineDocument = gql` + query GetAllTimeline($pageInfo: PageInfoTimeline!, $search: String, $sort: SortTimeline, $onlyUserFavorite: Boolean) { + getAllTimeline(pageInfo: $pageInfo, search: $search, sort: $sort, onlyUserFavorite: $onlyUserFavorite) { + totalCount + timeline { + savedObjectId + description + favorite { + fullName + userName + favoriteDate + } + eventIdToNoteIds { + eventId + note + timelineId + noteId + created + createdBy + timelineVersion + updated + updatedBy + version + } + notes { + eventId + note + timelineId + timelineVersion + noteId + created + createdBy + updated + updatedBy + version + } + noteIds + pinnedEventIds + title + created + createdBy + updated + updatedBy + version + } + } +} + `; +export type GetAllTimelineComponentProps = Omit, 'query'> & ({ variables: GetAllTimelineQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetAllTimelineComponent = (props: GetAllTimelineComponentProps) => ( + query={GetAllTimelineDocument} {...props} /> + ); + + +/** + * __useGetAllTimelineQuery__ + * + * To run a query within a React component, call `useGetAllTimelineQuery` and pass it any options that fit your needs. + * When your component renders, `useGetAllTimelineQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetAllTimelineQuery({ + * variables: { + * pageInfo: // value for 'pageInfo' + * search: // value for 'search' + * sort: // value for 'sort' + * onlyUserFavorite: // value for 'onlyUserFavorite' + * }, + * }); + */ +export function useGetAllTimelineQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetAllTimelineDocument, baseOptions); + } +export function useGetAllTimelineLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetAllTimelineDocument, baseOptions); + } +export type GetAllTimelineQueryHookResult = ReturnType; +export type GetAllTimelineLazyQueryHookResult = ReturnType; +export type GetAllTimelineQueryResult = ApolloReactCommon.QueryResult; +export const DeleteTimelineMutationDocument = gql` + mutation DeleteTimelineMutation($id: [ID!]!) { + deleteTimeline(id: $id) +} + `; +export type DeleteTimelineMutationMutationFn = ApolloReactCommon.MutationFunction; +export type DeleteTimelineMutationComponentProps = Omit, 'mutation'>; + + export const DeleteTimelineMutationComponent = (props: DeleteTimelineMutationComponentProps) => ( + mutation={DeleteTimelineMutationDocument} {...props} /> + ); + + +/** + * __useDeleteTimelineMutationMutation__ + * + * To run a mutation, you first call `useDeleteTimelineMutationMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useDeleteTimelineMutationMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [deleteTimelineMutationMutation, { data, loading, error }] = useDeleteTimelineMutationMutation({ + * variables: { + * id: // value for 'id' + * }, + * }); + */ +export function useDeleteTimelineMutationMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(DeleteTimelineMutationDocument, baseOptions); + } +export type DeleteTimelineMutationMutationHookResult = ReturnType; +export type DeleteTimelineMutationMutationResult = ApolloReactCommon.MutationResult; +export type DeleteTimelineMutationMutationOptions = ApolloReactCommon.BaseMutationOptions; +export const GetTimelineDetailsQueryDocument = gql` + query GetTimelineDetailsQuery($sourceId: ID!, $eventId: String!, $indexName: String!, $defaultIndex: [String!]!) { + source(id: $sourceId) { + id + TimelineDetails(eventId: $eventId, indexName: $indexName, defaultIndex: $defaultIndex) { + data { + field + values + originalValue + } + } + } +} + `; +export type GetTimelineDetailsQueryComponentProps = Omit, 'query'> & ({ variables: GetTimelineDetailsQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetTimelineDetailsQueryComponent = (props: GetTimelineDetailsQueryComponentProps) => ( + query={GetTimelineDetailsQueryDocument} {...props} /> + ); + + +/** + * __useGetTimelineDetailsQueryQuery__ + * + * To run a query within a React component, call `useGetTimelineDetailsQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetTimelineDetailsQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetTimelineDetailsQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * eventId: // value for 'eventId' + * indexName: // value for 'indexName' + * defaultIndex: // value for 'defaultIndex' + * }, + * }); + */ +export function useGetTimelineDetailsQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetTimelineDetailsQueryDocument, baseOptions); + } +export function useGetTimelineDetailsQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetTimelineDetailsQueryDocument, baseOptions); + } +export type GetTimelineDetailsQueryQueryHookResult = ReturnType; +export type GetTimelineDetailsQueryLazyQueryHookResult = ReturnType; +export type GetTimelineDetailsQueryQueryResult = ApolloReactCommon.QueryResult; +export const PersistTimelineFavoriteMutationDocument = gql` + mutation PersistTimelineFavoriteMutation($timelineId: ID) { + persistFavorite(timelineId: $timelineId) { + savedObjectId + version + favorite { + fullName + userName + favoriteDate + } + } +} + `; +export type PersistTimelineFavoriteMutationMutationFn = ApolloReactCommon.MutationFunction; +export type PersistTimelineFavoriteMutationComponentProps = Omit, 'mutation'>; + + export const PersistTimelineFavoriteMutationComponent = (props: PersistTimelineFavoriteMutationComponentProps) => ( + mutation={PersistTimelineFavoriteMutationDocument} {...props} /> + ); + + +/** + * __usePersistTimelineFavoriteMutationMutation__ + * + * To run a mutation, you first call `usePersistTimelineFavoriteMutationMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `usePersistTimelineFavoriteMutationMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [persistTimelineFavoriteMutationMutation, { data, loading, error }] = usePersistTimelineFavoriteMutationMutation({ + * variables: { + * timelineId: // value for 'timelineId' + * }, + * }); + */ +export function usePersistTimelineFavoriteMutationMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(PersistTimelineFavoriteMutationDocument, baseOptions); + } +export type PersistTimelineFavoriteMutationMutationHookResult = ReturnType; +export type PersistTimelineFavoriteMutationMutationResult = ApolloReactCommon.MutationResult; +export type PersistTimelineFavoriteMutationMutationOptions = ApolloReactCommon.BaseMutationOptions; +export const GetTimelineQueryDocument = gql` + query GetTimelineQuery($sourceId: ID!, $fieldRequested: [String!]!, $pagination: PaginationInput!, $sortField: SortField!, $filterQuery: String, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + Timeline(fieldRequested: $fieldRequested, pagination: $pagination, sortField: $sortField, filterQuery: $filterQuery, defaultIndex: $defaultIndex) { + totalCount + inspect @include(if: $inspect) { + dsl + response + } + pageInfo { + endCursor { + value + tiebreaker + } + hasNextPage + } + edges { + node { + _id + _index + data { + field + value + } + ecs { + _id + _index + timestamp + message + system { + auth { + ssh { + signature + method + } + } + audit { + package { + arch + entity_id + name + size + summary + version + } + } + } + event { + action + category + code + created + dataset + duration + end + hash + id + kind + module + original + outcome + risk_score + risk_score_norm + severity + start + timezone + type + } + auditd { + result + session + data { + acct + terminal + op + } + summary { + actor { + primary + secondary + } + object { + primary + secondary + type + } + how + message_type + sequence + } + } + file { + name + path + target_path + extension + type + device + inode + uid + owner + gid + group + mode + size + mtime + ctime + } + host { + id + name + ip + } + rule { + reference + } + source { + bytes + ip + packets + port + geo { + continent_name + country_name + country_iso_code + city_name + region_iso_code + region_name + } + } + destination { + bytes + ip + packets + port + geo { + continent_name + country_name + country_iso_code + city_name + region_iso_code + region_name + } + } + dns { + question { + name + type + } + resolved_ip + response_code + } + endgame { + exit_code + file_name + file_path + logon_type + parent_process_name + pid + process_name + subject_domain_name + subject_logon_id + subject_user_name + target_domain_name + target_logon_id + target_user_name + } + geo { + region_name + country_iso_code + } + signal { + original_time + rule { + id + saved_id + timeline_id + timeline_title + output_index + from + index + language + query + to + filters + } + } + suricata { + eve { + proto + flow_id + alert { + signature + signature_id + } + } + } + network { + bytes + community_id + direction + packets + protocol + transport + } + http { + version + request { + method + body { + bytes + content + } + referrer + } + response { + status_code + body { + bytes + content + } + } + } + tls { + client_certificate { + fingerprint { + sha1 + } + } + fingerprints { + ja3 { + hash + } + } + server_certificate { + fingerprint { + sha1 + } + } + } + url { + original + domain + username + password + } + user { + domain + name + } + winlog { + event_id + } + process { + hash { + md5 + sha1 + sha256 + } + pid + name + ppid + args + executable + title + working_directory + } + zeek { + session_id + connection { + local_resp + local_orig + missed_bytes + state + history + } + notice { + suppress_for + msg + note + sub + dst + dropped + peer_descr + } + dns { + AA + qclass_name + RD + qtype_name + rejected + qtype + query + trans_id + qclass + RA + TC + } + http { + resp_mime_types + trans_depth + status_msg + resp_fuids + tags + } + files { + session_ids + timedout + local_orig + tx_host + source + is_orig + overflow_bytes + sha1 + duration + depth + analyzers + mime_type + rx_host + total_bytes + fuid + seen_bytes + missing_bytes + md5 + } + ssl { + cipher + established + resumed + version + } + } + } + } + } + } + } +} + `; +export type GetTimelineQueryComponentProps = Omit, 'query'> & ({ variables: GetTimelineQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetTimelineQueryComponent = (props: GetTimelineQueryComponentProps) => ( + query={GetTimelineQueryDocument} {...props} /> + ); + + +/** + * __useGetTimelineQueryQuery__ + * + * To run a query within a React component, call `useGetTimelineQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetTimelineQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetTimelineQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * fieldRequested: // value for 'fieldRequested' + * pagination: // value for 'pagination' + * sortField: // value for 'sortField' + * filterQuery: // value for 'filterQuery' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetTimelineQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetTimelineQueryDocument, baseOptions); + } +export function useGetTimelineQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetTimelineQueryDocument, baseOptions); + } +export type GetTimelineQueryQueryHookResult = ReturnType; +export type GetTimelineQueryLazyQueryHookResult = ReturnType; +export type GetTimelineQueryQueryResult = ApolloReactCommon.QueryResult; +export const PersistTimelineNoteMutationDocument = gql` + mutation PersistTimelineNoteMutation($noteId: ID, $version: String, $note: NoteInput!) { + persistNote(noteId: $noteId, version: $version, note: $note) { + code + message + note { + eventId + note + timelineId + timelineVersion + noteId + created + createdBy + updated + updatedBy + version + } + } +} + `; +export type PersistTimelineNoteMutationMutationFn = ApolloReactCommon.MutationFunction; +export type PersistTimelineNoteMutationComponentProps = Omit, 'mutation'>; + + export const PersistTimelineNoteMutationComponent = (props: PersistTimelineNoteMutationComponentProps) => ( + mutation={PersistTimelineNoteMutationDocument} {...props} /> + ); + + +/** + * __usePersistTimelineNoteMutationMutation__ + * + * To run a mutation, you first call `usePersistTimelineNoteMutationMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `usePersistTimelineNoteMutationMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [persistTimelineNoteMutationMutation, { data, loading, error }] = usePersistTimelineNoteMutationMutation({ + * variables: { + * noteId: // value for 'noteId' + * version: // value for 'version' + * note: // value for 'note' + * }, + * }); + */ +export function usePersistTimelineNoteMutationMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(PersistTimelineNoteMutationDocument, baseOptions); + } +export type PersistTimelineNoteMutationMutationHookResult = ReturnType; +export type PersistTimelineNoteMutationMutationResult = ApolloReactCommon.MutationResult; +export type PersistTimelineNoteMutationMutationOptions = ApolloReactCommon.BaseMutationOptions; +export const GetOneTimelineDocument = gql` + query GetOneTimeline($id: ID!) { + getOneTimeline(id: $id) { + savedObjectId + columns { + aggregatable + category + columnHeaderType + description + example + indexes + id + name + searchable + type + } + dataProviders { + id + name + enabled + excluded + kqlQuery + queryMatch { + field + displayField + value + displayValue + operator + } + and { + id + name + enabled + excluded + kqlQuery + queryMatch { + field + displayField + value + displayValue + operator + } + } + } + dateRange { + start + end + } + description + eventType + eventIdToNoteIds { + eventId + note + timelineId + noteId + created + createdBy + timelineVersion + updated + updatedBy + version + } + favorite { + fullName + userName + favoriteDate + } + filters { + meta { + alias + controlledBy + disabled + field + formattedValue + index + key + negate + params + type + value + } + query + exists + match_all + missing + range + script + } + kqlMode + kqlQuery { + filterQuery { + kuery { + kind + expression + } + serializedQuery + } + } + notes { + eventId + note + timelineId + timelineVersion + noteId + created + createdBy + updated + updatedBy + version + } + noteIds + pinnedEventIds + pinnedEventsSaveObject { + pinnedEventId + eventId + timelineId + created + createdBy + updated + updatedBy + version + } + title + savedQueryId + sort { + columnId + sortDirection + } + created + createdBy + updated + updatedBy + version + } +} + `; +export type GetOneTimelineComponentProps = Omit, 'query'> & ({ variables: GetOneTimelineQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetOneTimelineComponent = (props: GetOneTimelineComponentProps) => ( + query={GetOneTimelineDocument} {...props} /> + ); + + +/** + * __useGetOneTimelineQuery__ + * + * To run a query within a React component, call `useGetOneTimelineQuery` and pass it any options that fit your needs. + * When your component renders, `useGetOneTimelineQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetOneTimelineQuery({ + * variables: { + * id: // value for 'id' + * }, + * }); + */ +export function useGetOneTimelineQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetOneTimelineDocument, baseOptions); + } +export function useGetOneTimelineLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetOneTimelineDocument, baseOptions); + } +export type GetOneTimelineQueryHookResult = ReturnType; +export type GetOneTimelineLazyQueryHookResult = ReturnType; +export type GetOneTimelineQueryResult = ApolloReactCommon.QueryResult; +export const PersistTimelineMutationDocument = gql` + mutation PersistTimelineMutation($timelineId: ID, $version: String, $timeline: TimelineInput!) { + persistTimeline(id: $timelineId, version: $version, timeline: $timeline) { + code + message + timeline { + savedObjectId + version + columns { + aggregatable + category + columnHeaderType + description + example + indexes + id + name + searchable + type + } + dataProviders { + id + name + enabled + excluded + kqlQuery + queryMatch { + field + displayField + value + displayValue + operator + } + and { + id + name + enabled + excluded + kqlQuery + queryMatch { + field + displayField + value + displayValue + operator + } + } + } + description + eventType + favorite { + fullName + userName + favoriteDate + } + filters { + meta { + alias + controlledBy + disabled + field + formattedValue + index + key + negate + params + type + value + } + query + exists + match_all + missing + range + script + } + kqlMode + kqlQuery { + filterQuery { + kuery { + kind + expression + } + serializedQuery + } + } + title + dateRange { + start + end + } + savedQueryId + sort { + columnId + sortDirection + } + created + createdBy + updated + updatedBy + } + } +} + `; +export type PersistTimelineMutationMutationFn = ApolloReactCommon.MutationFunction; +export type PersistTimelineMutationComponentProps = Omit, 'mutation'>; + + export const PersistTimelineMutationComponent = (props: PersistTimelineMutationComponentProps) => ( + mutation={PersistTimelineMutationDocument} {...props} /> + ); + + +/** + * __usePersistTimelineMutationMutation__ + * + * To run a mutation, you first call `usePersistTimelineMutationMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `usePersistTimelineMutationMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [persistTimelineMutationMutation, { data, loading, error }] = usePersistTimelineMutationMutation({ + * variables: { + * timelineId: // value for 'timelineId' + * version: // value for 'version' + * timeline: // value for 'timeline' + * }, + * }); + */ +export function usePersistTimelineMutationMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(PersistTimelineMutationDocument, baseOptions); + } +export type PersistTimelineMutationMutationHookResult = ReturnType; +export type PersistTimelineMutationMutationResult = ApolloReactCommon.MutationResult; +export type PersistTimelineMutationMutationOptions = ApolloReactCommon.BaseMutationOptions; +export const PersistTimelinePinnedEventMutationDocument = gql` + mutation PersistTimelinePinnedEventMutation($pinnedEventId: ID, $eventId: ID!, $timelineId: ID) { + persistPinnedEventOnTimeline(pinnedEventId: $pinnedEventId, eventId: $eventId, timelineId: $timelineId) { + pinnedEventId + eventId + timelineId + timelineVersion + created + createdBy + updated + updatedBy + version + } +} + `; +export type PersistTimelinePinnedEventMutationMutationFn = ApolloReactCommon.MutationFunction; +export type PersistTimelinePinnedEventMutationComponentProps = Omit, 'mutation'>; + + export const PersistTimelinePinnedEventMutationComponent = (props: PersistTimelinePinnedEventMutationComponentProps) => ( + mutation={PersistTimelinePinnedEventMutationDocument} {...props} /> + ); + + +/** + * __usePersistTimelinePinnedEventMutationMutation__ + * + * To run a mutation, you first call `usePersistTimelinePinnedEventMutationMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `usePersistTimelinePinnedEventMutationMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [persistTimelinePinnedEventMutationMutation, { data, loading, error }] = usePersistTimelinePinnedEventMutationMutation({ + * variables: { + * pinnedEventId: // value for 'pinnedEventId' + * eventId: // value for 'eventId' + * timelineId: // value for 'timelineId' + * }, + * }); + */ +export function usePersistTimelinePinnedEventMutationMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(PersistTimelinePinnedEventMutationDocument, baseOptions); + } +export type PersistTimelinePinnedEventMutationMutationHookResult = ReturnType; +export type PersistTimelinePinnedEventMutationMutationResult = ApolloReactCommon.MutationResult; +export type PersistTimelinePinnedEventMutationMutationOptions = ApolloReactCommon.BaseMutationOptions; +export const GetTlsQueryDocument = gql` + query GetTlsQuery($sourceId: ID!, $filterQuery: String, $flowTarget: FlowTargetSourceDest!, $ip: String!, $pagination: PaginationInputPaginated!, $sort: TlsSortField!, $timerange: TimerangeInput!, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + Tls(filterQuery: $filterQuery, flowTarget: $flowTarget, ip: $ip, pagination: $pagination, sort: $sort, timerange: $timerange, defaultIndex: $defaultIndex) { + totalCount + edges { + node { + _id + alternativeNames + commonNames + ja3 + issuerNames + notAfter + } + cursor { + value + } + } + pageInfo { + activePage + fakeTotalCount + showMorePagesIndicator + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetTlsQueryComponentProps = Omit, 'query'> & ({ variables: GetTlsQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetTlsQueryComponent = (props: GetTlsQueryComponentProps) => ( + query={GetTlsQueryDocument} {...props} /> + ); + + +/** + * __useGetTlsQueryQuery__ + * + * To run a query within a React component, call `useGetTlsQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetTlsQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetTlsQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * filterQuery: // value for 'filterQuery' + * flowTarget: // value for 'flowTarget' + * ip: // value for 'ip' + * pagination: // value for 'pagination' + * sort: // value for 'sort' + * timerange: // value for 'timerange' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetTlsQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetTlsQueryDocument, baseOptions); + } +export function useGetTlsQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetTlsQueryDocument, baseOptions); + } +export type GetTlsQueryQueryHookResult = ReturnType; +export type GetTlsQueryLazyQueryHookResult = ReturnType; +export type GetTlsQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetUncommonProcessesQueryDocument = gql` + query GetUncommonProcessesQuery($sourceId: ID!, $timerange: TimerangeInput!, $pagination: PaginationInputPaginated!, $filterQuery: String, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + UncommonProcesses(timerange: $timerange, pagination: $pagination, filterQuery: $filterQuery, defaultIndex: $defaultIndex) { + totalCount + edges { + node { + _id + instances + process { + args + name + } + user { + id + name + } + hosts { + name + } + } + cursor { + value + } + } + pageInfo { + activePage + fakeTotalCount + showMorePagesIndicator + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetUncommonProcessesQueryComponentProps = Omit, 'query'> & ({ variables: GetUncommonProcessesQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetUncommonProcessesQueryComponent = (props: GetUncommonProcessesQueryComponentProps) => ( + query={GetUncommonProcessesQueryDocument} {...props} /> + ); + + +/** + * __useGetUncommonProcessesQueryQuery__ + * + * To run a query within a React component, call `useGetUncommonProcessesQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetUncommonProcessesQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetUncommonProcessesQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * timerange: // value for 'timerange' + * pagination: // value for 'pagination' + * filterQuery: // value for 'filterQuery' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetUncommonProcessesQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetUncommonProcessesQueryDocument, baseOptions); + } +export function useGetUncommonProcessesQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetUncommonProcessesQueryDocument, baseOptions); + } +export type GetUncommonProcessesQueryQueryHookResult = ReturnType; +export type GetUncommonProcessesQueryLazyQueryHookResult = ReturnType; +export type GetUncommonProcessesQueryQueryResult = ApolloReactCommon.QueryResult; +export const GetUsersQueryDocument = gql` + query GetUsersQuery($sourceId: ID!, $filterQuery: String, $flowTarget: FlowTarget!, $ip: String!, $pagination: PaginationInputPaginated!, $sort: UsersSortField!, $timerange: TimerangeInput!, $defaultIndex: [String!]!, $inspect: Boolean!) { + source(id: $sourceId) { + id + Users(filterQuery: $filterQuery, flowTarget: $flowTarget, ip: $ip, pagination: $pagination, sort: $sort, timerange: $timerange, defaultIndex: $defaultIndex) { + totalCount + edges { + node { + user { + name + id + groupId + groupName + count + } + } + cursor { + value + } + } + pageInfo { + activePage + fakeTotalCount + showMorePagesIndicator + } + inspect @include(if: $inspect) { + dsl + response + } + } + } +} + `; +export type GetUsersQueryComponentProps = Omit, 'query'> & ({ variables: GetUsersQueryQueryVariables; skip?: boolean; } | { skip: boolean; }); + + export const GetUsersQueryComponent = (props: GetUsersQueryComponentProps) => ( + query={GetUsersQueryDocument} {...props} /> + ); + + +/** + * __useGetUsersQueryQuery__ + * + * To run a query within a React component, call `useGetUsersQueryQuery` and pass it any options that fit your needs. + * When your component renders, `useGetUsersQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetUsersQueryQuery({ + * variables: { + * sourceId: // value for 'sourceId' + * filterQuery: // value for 'filterQuery' + * flowTarget: // value for 'flowTarget' + * ip: // value for 'ip' + * pagination: // value for 'pagination' + * sort: // value for 'sort' + * timerange: // value for 'timerange' + * defaultIndex: // value for 'defaultIndex' + * inspect: // value for 'inspect' + * }, + * }); + */ +export function useGetUsersQueryQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(GetUsersQueryDocument, baseOptions); + } +export function useGetUsersQueryLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(GetUsersQueryDocument, baseOptions); + } +export type GetUsersQueryQueryHookResult = ReturnType; +export type GetUsersQueryLazyQueryHookResult = ReturnType; +export type GetUsersQueryQueryResult = ApolloReactCommon.QueryResult; +export namespace GetAuthenticationsQuery { + export type Variables = GetAuthenticationsQueryQueryVariables; + export type Query = GetAuthenticationsQueryQuery; + export type Source = GetAuthenticationsQueryQuery['source']; + export type Authentications = GetAuthenticationsQueryQuery['source']['Authentications']; + export type Edges = (NonNullable); + export type Node = (NonNullable)['node']; + export type User = (NonNullable)['node']['user']; + export type LastSuccess = (NonNullable<(NonNullable)['node']['lastSuccess']>); + export type _Source = (NonNullable<(NonNullable<(NonNullable)['node']['lastSuccess']>)['source']>); + export type Host = (NonNullable<(NonNullable<(NonNullable)['node']['lastSuccess']>)['host']>); + export type LastFailure = (NonNullable<(NonNullable)['node']['lastFailure']>); + export type __Source = (NonNullable<(NonNullable<(NonNullable)['node']['lastFailure']>)['source']>); + export type _Host = (NonNullable<(NonNullable<(NonNullable)['node']['lastFailure']>)['host']>); + export type Cursor = (NonNullable)['cursor']; + export type PageInfo = GetAuthenticationsQueryQuery['source']['Authentications']['pageInfo']; + export type Inspect = (NonNullable); + export const Document = GetAuthenticationsQueryDocument; + export const Component = GetAuthenticationsQueryComponent; + export const use = useGetAuthenticationsQueryQuery; +} + +export namespace GetLastEventTimeQuery { + export type Variables = GetLastEventTimeQueryQueryVariables; + export type Query = GetLastEventTimeQueryQuery; + export type Source = GetLastEventTimeQueryQuery['source']; + export type LastEventTime = GetLastEventTimeQueryQuery['source']['LastEventTime']; + export const Document = GetLastEventTimeQueryDocument; + export const Component = GetLastEventTimeQueryComponent; + export const use = useGetLastEventTimeQueryQuery; +} + +export namespace GetHostFirstLastSeenQuery { + export type Variables = GetHostFirstLastSeenQueryQueryVariables; + export type Query = GetHostFirstLastSeenQueryQuery; + export type Source = GetHostFirstLastSeenQueryQuery['source']; + export type HostFirstLastSeen = GetHostFirstLastSeenQueryQuery['source']['HostFirstLastSeen']; + export const Document = GetHostFirstLastSeenQueryDocument; + export const Component = GetHostFirstLastSeenQueryComponent; + export const use = useGetHostFirstLastSeenQueryQuery; +} + +export namespace GetHostsTableQuery { + export type Variables = GetHostsTableQueryQueryVariables; + export type Query = GetHostsTableQueryQuery; + export type Source = GetHostsTableQueryQuery['source']; + export type Hosts = GetHostsTableQueryQuery['source']['Hosts']; + export type Edges = (NonNullable); + export type Node = (NonNullable)['node']; + export type Host = (NonNullable<(NonNullable)['node']['host']>); + export type Os = (NonNullable<(NonNullable<(NonNullable)['node']['host']>)['os']>); + export type Cursor = (NonNullable)['cursor']; + export type PageInfo = GetHostsTableQueryQuery['source']['Hosts']['pageInfo']; + export type Inspect = (NonNullable); + export const Document = GetHostsTableQueryDocument; + export const Component = GetHostsTableQueryComponent; + export const use = useGetHostsTableQueryQuery; +} + +export namespace GetHostOverviewQuery { + export type Variables = GetHostOverviewQueryQueryVariables; + export type Query = GetHostOverviewQueryQuery; + export type Source = GetHostOverviewQueryQuery['source']; + export type HostOverview = GetHostOverviewQueryQuery['source']['HostOverview']; + export type Host = (NonNullable); + export type Os = (NonNullable<(NonNullable)['os']>); + export type Cloud = (NonNullable); + export type Instance = (NonNullable<(NonNullable)['instance']>); + export type Machine = (NonNullable<(NonNullable)['machine']>); + export type Inspect = (NonNullable); + export const Document = GetHostOverviewQueryDocument; + export const Component = GetHostOverviewQueryComponent; + export const use = useGetHostOverviewQueryQuery; +} + +export namespace GetIpOverviewQuery { + export type Variables = GetIpOverviewQueryQueryVariables; + export type Query = GetIpOverviewQueryQuery; + export type Source = GetIpOverviewQueryQuery['source']; + export type IpOverview = (NonNullable); + export type _Source = (NonNullable<(NonNullable)['source']>); + export type AutonomousSystem = (NonNullable<(NonNullable)['source']>)['autonomousSystem']; + export type Organization = (NonNullable<(NonNullable<(NonNullable)['source']>)['autonomousSystem']['organization']>); + export type Geo = (NonNullable<(NonNullable)['source']>)['geo']; + export type Location = (NonNullable<(NonNullable<(NonNullable)['source']>)['geo']['location']>); + export type Destination = (NonNullable<(NonNullable)['destination']>); + export type _AutonomousSystem = (NonNullable<(NonNullable)['destination']>)['autonomousSystem']; + export type _Organization = (NonNullable<(NonNullable<(NonNullable)['destination']>)['autonomousSystem']['organization']>); + export type _Geo = (NonNullable<(NonNullable)['destination']>)['geo']; + export type _Location = (NonNullable<(NonNullable<(NonNullable)['destination']>)['geo']['location']>); + export type Host = (NonNullable)['host']; + export type Os = (NonNullable<(NonNullable)['host']['os']>); + export type Inspect = (NonNullable<(NonNullable)['inspect']>); + export const Document = GetIpOverviewQueryDocument; + export const Component = GetIpOverviewQueryComponent; + export const use = useGetIpOverviewQueryQuery; +} + +export namespace KpiHostDetailsChartFields { + export type Fragment = KpiHostDetailsChartFieldsFragment; +} + +export namespace GetKpiHostDetailsQuery { + export type Variables = GetKpiHostDetailsQueryQueryVariables; + export type Query = GetKpiHostDetailsQueryQuery; + export type Source = GetKpiHostDetailsQueryQuery['source']; + export type KpiHostDetails = GetKpiHostDetailsQueryQuery['source']['KpiHostDetails']; + export type AuthSuccessHistogram = KpiHostDetailsChartFieldsFragment; + export type AuthFailureHistogram = KpiHostDetailsChartFieldsFragment; + export type UniqueSourceIpsHistogram = KpiHostDetailsChartFieldsFragment; + export type UniqueDestinationIpsHistogram = KpiHostDetailsChartFieldsFragment; + export type Inspect = (NonNullable); + export const Document = GetKpiHostDetailsQueryDocument; + export const Component = GetKpiHostDetailsQueryComponent; + export const use = useGetKpiHostDetailsQueryQuery; +} + +export namespace KpiHostChartFields { + export type Fragment = KpiHostChartFieldsFragment; +} + +export namespace GetKpiHostsQuery { + export type Variables = GetKpiHostsQueryQueryVariables; + export type Query = GetKpiHostsQueryQuery; + export type Source = GetKpiHostsQueryQuery['source']; + export type KpiHosts = GetKpiHostsQueryQuery['source']['KpiHosts']; + export type HostsHistogram = KpiHostChartFieldsFragment; + export type AuthSuccessHistogram = KpiHostChartFieldsFragment; + export type AuthFailureHistogram = KpiHostChartFieldsFragment; + export type UniqueSourceIpsHistogram = KpiHostChartFieldsFragment; + export type UniqueDestinationIpsHistogram = KpiHostChartFieldsFragment; + export type Inspect = (NonNullable); + export const Document = GetKpiHostsQueryDocument; + export const Component = GetKpiHostsQueryComponent; + export const use = useGetKpiHostsQueryQuery; +} + +export namespace KpiNetworkChartFields { + export type Fragment = KpiNetworkChartFieldsFragment; +} + +export namespace GetKpiNetworkQuery { + export type Variables = GetKpiNetworkQueryQueryVariables; + export type Query = GetKpiNetworkQueryQuery; + export type Source = GetKpiNetworkQueryQuery['source']; + export type KpiNetwork = (NonNullable); + export type UniqueSourcePrivateIpsHistogram = KpiNetworkChartFieldsFragment; + export type UniqueDestinationPrivateIpsHistogram = KpiNetworkChartFieldsFragment; + export type Inspect = (NonNullable<(NonNullable)['inspect']>); + export const Document = GetKpiNetworkQueryDocument; + export const Component = GetKpiNetworkQueryComponent; + export const use = useGetKpiNetworkQueryQuery; +} + +export namespace GetMatrixHistogramQuery { + export type Variables = GetMatrixHistogramQueryQueryVariables; + export type Query = GetMatrixHistogramQueryQuery; + export type Source = GetMatrixHistogramQueryQuery['source']; + export type MatrixHistogram = GetMatrixHistogramQueryQuery['source']['MatrixHistogram']; + export type MatrixHistogramData = (NonNullable); + export type Inspect = (NonNullable); + export const Document = GetMatrixHistogramQueryDocument; + export const Component = GetMatrixHistogramQueryComponent; + export const use = useGetMatrixHistogramQueryQuery; +} + +export namespace GetNetworkDnsQuery { + export type Variables = GetNetworkDnsQueryQueryVariables; + export type Query = GetNetworkDnsQueryQuery; + export type Source = GetNetworkDnsQueryQuery['source']; + export type NetworkDns = GetNetworkDnsQueryQuery['source']['NetworkDns']; + export type Edges = (NonNullable); + export type Node = (NonNullable)['node']; + export type Cursor = (NonNullable)['cursor']; + export type PageInfo = GetNetworkDnsQueryQuery['source']['NetworkDns']['pageInfo']; + export type Inspect = (NonNullable); + export const Document = GetNetworkDnsQueryDocument; + export const Component = GetNetworkDnsQueryComponent; + export const use = useGetNetworkDnsQueryQuery; +} + +export namespace GetNetworkHttpQuery { + export type Variables = GetNetworkHttpQueryQueryVariables; + export type Query = GetNetworkHttpQueryQuery; + export type Source = GetNetworkHttpQueryQuery['source']; + export type NetworkHttp = GetNetworkHttpQueryQuery['source']['NetworkHttp']; + export type Edges = (NonNullable); + export type Node = (NonNullable)['node']; + export type Cursor = (NonNullable)['cursor']; + export type PageInfo = GetNetworkHttpQueryQuery['source']['NetworkHttp']['pageInfo']; + export type Inspect = (NonNullable); + export const Document = GetNetworkHttpQueryDocument; + export const Component = GetNetworkHttpQueryComponent; + export const use = useGetNetworkHttpQueryQuery; +} + +export namespace GetNetworkTopCountriesQuery { + export type Variables = GetNetworkTopCountriesQueryQueryVariables; + export type Query = GetNetworkTopCountriesQueryQuery; + export type Source = GetNetworkTopCountriesQueryQuery['source']; + export type NetworkTopCountries = GetNetworkTopCountriesQueryQuery['source']['NetworkTopCountries']; + export type Edges = (NonNullable); + export type Node = (NonNullable)['node']; + export type _Source = (NonNullable<(NonNullable)['node']['source']>); + export type Destination = (NonNullable<(NonNullable)['node']['destination']>); + export type Network = (NonNullable<(NonNullable)['node']['network']>); + export type Cursor = (NonNullable)['cursor']; + export type PageInfo = GetNetworkTopCountriesQueryQuery['source']['NetworkTopCountries']['pageInfo']; + export type Inspect = (NonNullable); + export const Document = GetNetworkTopCountriesQueryDocument; + export const Component = GetNetworkTopCountriesQueryComponent; + export const use = useGetNetworkTopCountriesQueryQuery; +} + +export namespace GetNetworkTopNFlowQuery { + export type Variables = GetNetworkTopNFlowQueryQueryVariables; + export type Query = GetNetworkTopNFlowQueryQuery; + export type Source = GetNetworkTopNFlowQueryQuery['source']; + export type NetworkTopNFlow = GetNetworkTopNFlowQueryQuery['source']['NetworkTopNFlow']; + export type Edges = (NonNullable); + export type Node = (NonNullable)['node']; + export type _Source = (NonNullable<(NonNullable)['node']['source']>); + export type AutonomousSystem = (NonNullable<(NonNullable<(NonNullable)['node']['source']>)['autonomous_system']>); + export type Location = (NonNullable<(NonNullable<(NonNullable)['node']['source']>)['location']>); + export type Geo = (NonNullable<(NonNullable<(NonNullable<(NonNullable)['node']['source']>)['location']>)['geo']>); + export type Destination = (NonNullable<(NonNullable)['node']['destination']>); + export type _AutonomousSystem = (NonNullable<(NonNullable<(NonNullable)['node']['destination']>)['autonomous_system']>); + export type _Location = (NonNullable<(NonNullable<(NonNullable)['node']['destination']>)['location']>); + export type _Geo = (NonNullable<(NonNullable<(NonNullable<(NonNullable)['node']['destination']>)['location']>)['geo']>); + export type Network = (NonNullable<(NonNullable)['node']['network']>); + export type Cursor = (NonNullable)['cursor']; + export type PageInfo = GetNetworkTopNFlowQueryQuery['source']['NetworkTopNFlow']['pageInfo']; + export type Inspect = (NonNullable); + export const Document = GetNetworkTopNFlowQueryDocument; + export const Component = GetNetworkTopNFlowQueryComponent; + export const use = useGetNetworkTopNFlowQueryQuery; +} + +export namespace GetOverviewHostQuery { + export type Variables = GetOverviewHostQueryQueryVariables; + export type Query = GetOverviewHostQueryQuery; + export type Source = GetOverviewHostQueryQuery['source']; + export type OverviewHost = (NonNullable); + export type Inspect = (NonNullable<(NonNullable)['inspect']>); + export const Document = GetOverviewHostQueryDocument; + export const Component = GetOverviewHostQueryComponent; + export const use = useGetOverviewHostQueryQuery; +} + +export namespace GetOverviewNetworkQuery { + export type Variables = GetOverviewNetworkQueryQueryVariables; + export type Query = GetOverviewNetworkQueryQuery; + export type Source = GetOverviewNetworkQueryQuery['source']; + export type OverviewNetwork = (NonNullable); + export type Inspect = (NonNullable<(NonNullable)['inspect']>); + export const Document = GetOverviewNetworkQueryDocument; + export const Component = GetOverviewNetworkQueryComponent; + export const use = useGetOverviewNetworkQueryQuery; +} + +export namespace SourceQuery { + export type Variables = SourceQueryQueryVariables; + export type Query = SourceQueryQuery; + export type Source = SourceQueryQuery['source']; + export type Status = SourceQueryQuery['source']['status']; + export type IndexFields = (NonNullable); + export const Document = SourceQueryDocument; + export const Component = SourceQueryComponent; + export const use = useSourceQueryQuery; +} + +export namespace GetAllTimeline { + export type Variables = GetAllTimelineQueryVariables; + export type Query = GetAllTimelineQuery; + export type GetAllTimeline = GetAllTimelineQuery['getAllTimeline']; + export type Timeline = (NonNullable); + export type Favorite = (NonNullable<(NonNullable<(NonNullable)['favorite']>)[0]>); + export type EventIdToNoteIds = (NonNullable<(NonNullable<(NonNullable)['eventIdToNoteIds']>)[0]>); + export type Notes = (NonNullable<(NonNullable<(NonNullable)['notes']>)[0]>); + export const Document = GetAllTimelineDocument; + export const Component = GetAllTimelineComponent; + export const use = useGetAllTimelineQuery; +} + +export namespace DeleteTimelineMutation { + export type Variables = DeleteTimelineMutationMutationVariables; + export type Mutation = DeleteTimelineMutationMutation; + export const Document = DeleteTimelineMutationDocument; + export const Component = DeleteTimelineMutationComponent; + export const use = useDeleteTimelineMutationMutation; +} + +export namespace GetTimelineDetailsQuery { + export type Variables = GetTimelineDetailsQueryQueryVariables; + export type Query = GetTimelineDetailsQueryQuery; + export type Source = GetTimelineDetailsQueryQuery['source']; + export type TimelineDetails = GetTimelineDetailsQueryQuery['source']['TimelineDetails']; + export type Data = (NonNullable<(NonNullable)[0]>); + export const Document = GetTimelineDetailsQueryDocument; + export const Component = GetTimelineDetailsQueryComponent; + export const use = useGetTimelineDetailsQueryQuery; +} + +export namespace PersistTimelineFavoriteMutation { + export type Variables = PersistTimelineFavoriteMutationMutationVariables; + export type Mutation = PersistTimelineFavoriteMutationMutation; + export type PersistFavorite = PersistTimelineFavoriteMutationMutation['persistFavorite']; + export type Favorite = (NonNullable<(NonNullable)[0]>); + export const Document = PersistTimelineFavoriteMutationDocument; + export const Component = PersistTimelineFavoriteMutationComponent; + export const use = usePersistTimelineFavoriteMutationMutation; +} + +export namespace GetTimelineQuery { + export type Variables = GetTimelineQueryQueryVariables; + export type Query = GetTimelineQueryQuery; + export type Source = GetTimelineQueryQuery['source']; + export type Timeline = GetTimelineQueryQuery['source']['Timeline']; + export type Inspect = (NonNullable); + export type PageInfo = GetTimelineQueryQuery['source']['Timeline']['pageInfo']; + export type EndCursor = (NonNullable); + export type Edges = (NonNullable); + export type Node = (NonNullable)['node']; + export type Data = (NonNullable<(NonNullable)['node']['data'][0]>); + export type Ecs = (NonNullable)['node']['ecs']; + export type System = (NonNullable<(NonNullable)['node']['ecs']['system']>); + export type Auth = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['system']>)['auth']>); + export type Ssh = (NonNullable<(NonNullable<(NonNullable<(NonNullable)['node']['ecs']['system']>)['auth']>)['ssh']>); + export type Audit = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['system']>)['audit']>); + export type Package = (NonNullable<(NonNullable<(NonNullable<(NonNullable)['node']['ecs']['system']>)['audit']>)['package']>); + export type Event = (NonNullable<(NonNullable)['node']['ecs']['event']>); + export type Auditd = (NonNullable<(NonNullable)['node']['ecs']['auditd']>); + export type _Data = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['auditd']>)['data']>); + export type Summary = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['auditd']>)['summary']>); + export type Actor = (NonNullable<(NonNullable<(NonNullable<(NonNullable)['node']['ecs']['auditd']>)['summary']>)['actor']>); + export type Object = (NonNullable<(NonNullable<(NonNullable<(NonNullable)['node']['ecs']['auditd']>)['summary']>)['object']>); + export type File = (NonNullable<(NonNullable)['node']['ecs']['file']>); + export type Host = (NonNullable<(NonNullable)['node']['ecs']['host']>); + export type Rule = (NonNullable<(NonNullable)['node']['ecs']['rule']>); + export type _Source = (NonNullable<(NonNullable)['node']['ecs']['source']>); + export type Geo = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['source']>)['geo']>); + export type Destination = (NonNullable<(NonNullable)['node']['ecs']['destination']>); + export type _Geo = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['destination']>)['geo']>); + export type Dns = (NonNullable<(NonNullable)['node']['ecs']['dns']>); + export type Question = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['dns']>)['question']>); + export type Endgame = (NonNullable<(NonNullable)['node']['ecs']['endgame']>); + export type __Geo = (NonNullable<(NonNullable)['node']['ecs']['geo']>); + export type Signal = (NonNullable<(NonNullable)['node']['ecs']['signal']>); + export type _Rule = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['signal']>)['rule']>); + export type Suricata = (NonNullable<(NonNullable)['node']['ecs']['suricata']>); + export type Eve = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['suricata']>)['eve']>); + export type Alert = (NonNullable<(NonNullable<(NonNullable<(NonNullable)['node']['ecs']['suricata']>)['eve']>)['alert']>); + export type Network = (NonNullable<(NonNullable)['node']['ecs']['network']>); + export type Http = (NonNullable<(NonNullable)['node']['ecs']['http']>); + export type Request = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['http']>)['request']>); + export type Body = (NonNullable<(NonNullable<(NonNullable<(NonNullable)['node']['ecs']['http']>)['request']>)['body']>); + export type Response = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['http']>)['response']>); + export type _Body = (NonNullable<(NonNullable<(NonNullable<(NonNullable)['node']['ecs']['http']>)['response']>)['body']>); + export type Tls = (NonNullable<(NonNullable)['node']['ecs']['tls']>); + export type ClientCertificate = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['tls']>)['client_certificate']>); + export type Fingerprint = (NonNullable<(NonNullable<(NonNullable<(NonNullable)['node']['ecs']['tls']>)['client_certificate']>)['fingerprint']>); + export type Fingerprints = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['tls']>)['fingerprints']>); + export type Ja3 = (NonNullable<(NonNullable<(NonNullable<(NonNullable)['node']['ecs']['tls']>)['fingerprints']>)['ja3']>); + export type ServerCertificate = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['tls']>)['server_certificate']>); + export type _Fingerprint = (NonNullable<(NonNullable<(NonNullable<(NonNullable)['node']['ecs']['tls']>)['server_certificate']>)['fingerprint']>); + export type Url = (NonNullable<(NonNullable)['node']['ecs']['url']>); + export type User = (NonNullable<(NonNullable)['node']['ecs']['user']>); + export type Winlog = (NonNullable<(NonNullable)['node']['ecs']['winlog']>); + export type Process = (NonNullable<(NonNullable)['node']['ecs']['process']>); + export type Hash = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['process']>)['hash']>); + export type Zeek = (NonNullable<(NonNullable)['node']['ecs']['zeek']>); + export type Connection = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['zeek']>)['connection']>); + export type Notice = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['zeek']>)['notice']>); + export type _Dns = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['zeek']>)['dns']>); + export type _Http = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['zeek']>)['http']>); + export type Files = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['zeek']>)['files']>); + export type Ssl = (NonNullable<(NonNullable<(NonNullable)['node']['ecs']['zeek']>)['ssl']>); + export const Document = GetTimelineQueryDocument; + export const Component = GetTimelineQueryComponent; + export const use = useGetTimelineQueryQuery; +} + +export namespace PersistTimelineNoteMutation { + export type Variables = PersistTimelineNoteMutationMutationVariables; + export type Mutation = PersistTimelineNoteMutationMutation; + export type PersistNote = PersistTimelineNoteMutationMutation['persistNote']; + export type Note = PersistTimelineNoteMutationMutation['persistNote']['note']; + export const Document = PersistTimelineNoteMutationDocument; + export const Component = PersistTimelineNoteMutationComponent; + export const use = usePersistTimelineNoteMutationMutation; +} + +export namespace GetOneTimeline { + export type Variables = GetOneTimelineQueryVariables; + export type Query = GetOneTimelineQuery; + export type GetOneTimeline = GetOneTimelineQuery['getOneTimeline']; + export type Columns = (NonNullable<(NonNullable)[0]>); + export type DataProviders = (NonNullable<(NonNullable)[0]>); + export type QueryMatch = (NonNullable<(NonNullable<(NonNullable)[0]>)['queryMatch']>); + export type And = (NonNullable<(NonNullable<(NonNullable<(NonNullable)[0]>)['and']>)[0]>); + export type _QueryMatch = (NonNullable<(NonNullable<(NonNullable<(NonNullable<(NonNullable)[0]>)['and']>)[0]>)['queryMatch']>); + export type DateRange = (NonNullable); + export type EventIdToNoteIds = (NonNullable<(NonNullable)[0]>); + export type Favorite = (NonNullable<(NonNullable)[0]>); + export type Filters = (NonNullable<(NonNullable)[0]>); + export type Meta = (NonNullable<(NonNullable<(NonNullable)[0]>)['meta']>); + export type KqlQuery = (NonNullable); + export type FilterQuery = (NonNullable<(NonNullable)['filterQuery']>); + export type Kuery = (NonNullable<(NonNullable<(NonNullable)['filterQuery']>)['kuery']>); + export type Notes = (NonNullable<(NonNullable)[0]>); + export type PinnedEventsSaveObject = (NonNullable<(NonNullable)[0]>); + export type Sort = (NonNullable); + export const Document = GetOneTimelineDocument; + export const Component = GetOneTimelineComponent; + export const use = useGetOneTimelineQuery; +} + +export namespace PersistTimelineMutation { + export type Variables = PersistTimelineMutationMutationVariables; + export type Mutation = PersistTimelineMutationMutation; + export type PersistTimeline = PersistTimelineMutationMutation['persistTimeline']; + export type Timeline = PersistTimelineMutationMutation['persistTimeline']['timeline']; + export type Columns = (NonNullable<(NonNullable)[0]>); + export type DataProviders = (NonNullable<(NonNullable)[0]>); + export type QueryMatch = (NonNullable<(NonNullable<(NonNullable)[0]>)['queryMatch']>); + export type And = (NonNullable<(NonNullable<(NonNullable<(NonNullable)[0]>)['and']>)[0]>); + export type _QueryMatch = (NonNullable<(NonNullable<(NonNullable<(NonNullable<(NonNullable)[0]>)['and']>)[0]>)['queryMatch']>); + export type Favorite = (NonNullable<(NonNullable)[0]>); + export type Filters = (NonNullable<(NonNullable)[0]>); + export type Meta = (NonNullable<(NonNullable<(NonNullable)[0]>)['meta']>); + export type KqlQuery = (NonNullable); + export type FilterQuery = (NonNullable<(NonNullable)['filterQuery']>); + export type Kuery = (NonNullable<(NonNullable<(NonNullable)['filterQuery']>)['kuery']>); + export type DateRange = (NonNullable); + export type Sort = (NonNullable); + export const Document = PersistTimelineMutationDocument; + export const Component = PersistTimelineMutationComponent; + export const use = usePersistTimelineMutationMutation; +} + +export namespace PersistTimelinePinnedEventMutation { + export type Variables = PersistTimelinePinnedEventMutationMutationVariables; + export type Mutation = PersistTimelinePinnedEventMutationMutation; + export type PersistPinnedEventOnTimeline = (NonNullable); + export const Document = PersistTimelinePinnedEventMutationDocument; + export const Component = PersistTimelinePinnedEventMutationComponent; + export const use = usePersistTimelinePinnedEventMutationMutation; +} + +export namespace GetTlsQuery { + export type Variables = GetTlsQueryQueryVariables; + export type Query = GetTlsQueryQuery; + export type Source = GetTlsQueryQuery['source']; + export type Tls = GetTlsQueryQuery['source']['Tls']; + export type Edges = (NonNullable); + export type Node = (NonNullable)['node']; + export type Cursor = (NonNullable)['cursor']; + export type PageInfo = GetTlsQueryQuery['source']['Tls']['pageInfo']; + export type Inspect = (NonNullable); + export const Document = GetTlsQueryDocument; + export const Component = GetTlsQueryComponent; + export const use = useGetTlsQueryQuery; +} + +export namespace GetUncommonProcessesQuery { + export type Variables = GetUncommonProcessesQueryQueryVariables; + export type Query = GetUncommonProcessesQueryQuery; + export type Source = GetUncommonProcessesQueryQuery['source']; + export type UncommonProcesses = GetUncommonProcessesQueryQuery['source']['UncommonProcesses']; + export type Edges = (NonNullable); + export type Node = (NonNullable)['node']; + export type Process = (NonNullable)['node']['process']; + export type User = (NonNullable<(NonNullable)['node']['user']>); + export type Hosts = (NonNullable<(NonNullable)['node']['hosts'][0]>); + export type Cursor = (NonNullable)['cursor']; + export type PageInfo = GetUncommonProcessesQueryQuery['source']['UncommonProcesses']['pageInfo']; + export type Inspect = (NonNullable); + export const Document = GetUncommonProcessesQueryDocument; + export const Component = GetUncommonProcessesQueryComponent; + export const use = useGetUncommonProcessesQueryQuery; +} + +export namespace GetUsersQuery { + export type Variables = GetUsersQueryQueryVariables; + export type Query = GetUsersQueryQuery; + export type Source = GetUsersQueryQuery['source']; + export type Users = GetUsersQueryQuery['source']['Users']; + export type Edges = (NonNullable); + export type Node = (NonNullable)['node']; + export type User = (NonNullable<(NonNullable)['node']['user']>); + export type Cursor = (NonNullable)['cursor']; + export type PageInfo = GetUsersQueryQuery['source']['Users']['pageInfo']; + export type Inspect = (NonNullable); + export const Document = GetUsersQueryDocument; + export const Component = GetUsersQueryComponent; + export const use = useGetUsersQueryQuery; +} diff --git a/x-pack/legacy/plugins/siem/public/lib/compose/helpers.test.ts b/x-pack/legacy/plugins/siem/public/lib/compose/helpers.test.ts index af4521b4f6e2c..ae7d09d35bc3c 100644 --- a/x-pack/legacy/plugins/siem/public/lib/compose/helpers.test.ts +++ b/x-pack/legacy/plugins/siem/public/lib/compose/helpers.test.ts @@ -4,37 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ -import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; import { errorLink, reTryOneTimeOnErrorLink } from '../../containers/errors'; import { getLinks } from './helpers'; -import { withClientState } from 'apollo-link-state'; -import * as apolloLinkHttp from 'apollo-link-http'; -import introspectionQueryResultData from '../../graphql/introspection.json'; +import { HttpLink } from '@apollo/client'; -jest.mock('apollo-cache-inmemory'); -jest.mock('apollo-link-http'); -jest.mock('apollo-link-state'); +jest.mock('@apollo/client'); jest.mock('../../containers/errors'); -const mockWithClientState = 'mockWithClientState'; const mockHttpLink = { mockHttpLink: 'mockHttpLink' }; // @ts-ignore -withClientState.mockReturnValue(mockWithClientState); -// @ts-ignore -apolloLinkHttp.createHttpLink.mockImplementation(() => mockHttpLink); +HttpLink.mockImplementation(() => mockHttpLink); describe('getLinks helper', () => { test('It should return links in correct order', () => { - const mockCache = new InMemoryCache({ - dataIdFromObject: () => null, - fragmentMatcher: new IntrospectionFragmentMatcher({ - introspectionQueryResultData, - }), - }); - const links = getLinks(mockCache, 'basePath'); + const links = getLinks(''); expect(links[0]).toEqual(errorLink); expect(links[1]).toEqual(reTryOneTimeOnErrorLink); - expect(links[2]).toEqual(mockWithClientState); - expect(links[3]).toEqual(mockHttpLink); + expect(links[2]).toEqual(mockHttpLink); }); }); diff --git a/x-pack/legacy/plugins/siem/public/lib/compose/helpers.ts b/x-pack/legacy/plugins/siem/public/lib/compose/helpers.ts index b698fc55cc5e5..42ecdd211b927 100644 --- a/x-pack/legacy/plugins/siem/public/lib/compose/helpers.ts +++ b/x-pack/legacy/plugins/siem/public/lib/compose/helpers.ts @@ -4,20 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { createHttpLink } from 'apollo-link-http'; -import { withClientState } from 'apollo-link-state'; -import { InMemoryCache } from 'apollo-cache-inmemory'; +import { HttpLink } from '@apollo/client'; import { errorLink, reTryOneTimeOnErrorLink } from '../../containers/errors'; -export const getLinks = (cache: InMemoryCache, basePath: string) => [ +export const getLinks = (basePath: string) => [ errorLink, reTryOneTimeOnErrorLink, - withClientState({ - cache, - resolvers: {}, - }), - createHttpLink({ + new HttpLink({ credentials: 'same-origin', headers: { 'kbn-xsrf': 'true' }, uri: `${basePath}/api/siem/graphql`, diff --git a/x-pack/legacy/plugins/siem/public/lib/compose/kibana_compose.tsx b/x-pack/legacy/plugins/siem/public/lib/compose/kibana_compose.tsx index c742ced4c504c..3b670fb14e4b8 100644 --- a/x-pack/legacy/plugins/siem/public/lib/compose/kibana_compose.tsx +++ b/x-pack/legacy/plugins/siem/public/lib/compose/kibana_compose.tsx @@ -4,28 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ -import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; -import ApolloClient from 'apollo-client'; -import { ApolloLink } from 'apollo-link'; +import { ApolloClient, ApolloLink, InMemoryCache } from '@apollo/client'; -import introspectionQueryResultData from '../../graphql/introspection.json'; import { CoreStart } from '../../plugin'; import { AppFrontendLibs } from '../lib'; import { getLinks } from './helpers'; export function compose(core: CoreStart): AppFrontendLibs { - const cache = new InMemoryCache({ - dataIdFromObject: () => null, - fragmentMatcher: new IntrospectionFragmentMatcher({ - introspectionQueryResultData, - }), - }); const basePath = core.http.basePath.get(); const apolloClient = new ApolloClient({ connectToDevTools: process.env.NODE_ENV !== 'production', - cache, - link: ApolloLink.from(getLinks(cache, basePath)), + cache: new InMemoryCache({ + typePolicies: { + TimelineItem: { + keyFields: ['_id', '_index', 'data'], + }, + }, + }), + link: ApolloLink.from(getLinks(basePath)), }); const libs: AppFrontendLibs = { diff --git a/x-pack/legacy/plugins/siem/public/lib/lib.ts b/x-pack/legacy/plugins/siem/public/lib/lib.ts index e7b39d2ea50f9..084c62acef443 100644 --- a/x-pack/legacy/plugins/siem/public/lib/lib.ts +++ b/x-pack/legacy/plugins/siem/public/lib/lib.ts @@ -5,8 +5,7 @@ */ import { IScope } from 'angular'; -import { NormalizedCacheObject } from 'apollo-cache-inmemory'; -import ApolloClient from 'apollo-client'; +import { ApolloClient, NormalizedCacheObject } from '@apollo/client'; export interface AppFrontendLibs { apolloClient: AppApolloClient; diff --git a/x-pack/legacy/plugins/siem/public/mock/test_providers.tsx b/x-pack/legacy/plugins/siem/public/mock/test_providers.tsx index c7692755c1330..28e7b0deafa30 100644 --- a/x-pack/legacy/plugins/siem/public/mock/test_providers.tsx +++ b/x-pack/legacy/plugins/siem/public/mock/test_providers.tsx @@ -6,11 +6,8 @@ import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; import { I18nProvider } from '@kbn/i18n/react'; -import { InMemoryCache as Cache } from 'apollo-cache-inmemory'; -import ApolloClient from 'apollo-client'; -import { ApolloLink } from 'apollo-link'; import React from 'react'; -import { ApolloProvider } from 'react-apollo'; +import { ApolloProvider, ApolloClient, ApolloLink, InMemoryCache } from '@apollo/client'; import { DragDropContext, DropResult, ResponderProvided } from 'react-beautiful-dnd'; import { Provider as ReduxStoreProvider } from 'react-redux'; import { Store } from 'redux'; @@ -32,7 +29,7 @@ interface Props { } export const apolloClient = new ApolloClient({ - cache: new Cache(), + cache: new InMemoryCache(), link: new ApolloLink((o, f) => (f ? f(o) : null)), }); diff --git a/x-pack/legacy/plugins/siem/public/mock/timeline_results.ts b/x-pack/legacy/plugins/siem/public/mock/timeline_results.ts index d6dc0ae131391..26b8eb6bc5f15 100644 --- a/x-pack/legacy/plugins/siem/public/mock/timeline_results.ts +++ b/x-pack/legacy/plugins/siem/public/mock/timeline_results.ts @@ -4,15 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ +import { MockedResponse } from '@apollo/client/testing'; import { OpenTimelineResult } from '../components/open_timeline/types'; -import { GetAllTimeline, SortFieldTimeline, TimelineResult, Direction } from '../graphql/types'; +import { SortFieldTimeline, TimelineResult, Direction } from '../graphql/types'; import { allTimelinesQuery } from '../containers/timeline/all/index.gql_query'; -export interface MockedProvidedQuery { - request: { - query: GetAllTimeline.Query; - variables: GetAllTimeline.Variables; - }; +export interface MockedProvidedQuery extends MockedResponse { result: { data: { getAllTimeline: { @@ -22,6 +19,7 @@ export interface MockedProvidedQuery { }; }; } + /** Mocks results of a query run by the `OpenTimeline` component */ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ { diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/default_config.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/default_config.tsx index 44c48b1879e89..94015d6090468 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/default_config.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/default_config.tsx @@ -7,7 +7,7 @@ /* eslint-disable react/display-name */ import { EuiButtonIcon, EuiToolTip } from '@elastic/eui'; -import ApolloClient from 'apollo-client'; +import { ApolloClient } from '@apollo/client'; import React from 'react'; import { Filter } from '../../../../../../../../../src/plugins/data/common/es_query'; @@ -191,7 +191,7 @@ export const getSignalsActions = ({ status, updateTimelineIsLoading, }: { - apolloClient?: ApolloClient<{}>; + apolloClient?: ApolloClient; canUserCRUD: boolean; hasIndexWrite: boolean; setEventsLoading: ({ eventIds, isLoading }: SetEventsLoadingProps) => void; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/index.tsx index 75f19218d9b38..1e1ed8766de25 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/index.tsx @@ -9,6 +9,7 @@ import { isEmpty } from 'lodash/fp'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; +import { useApolloClient } from '@apollo/client'; import { Filter, esQuery } from '../../../../../../../../../src/plugins/data/public'; import { useFetchIndexPatterns } from '../../../../containers/detection_engine/rules/fetch_index_patterns'; @@ -20,7 +21,6 @@ import { inputsSelectors, State, inputsModel } from '../../../../store'; import { timelineActions, timelineSelectors } from '../../../../store/timeline'; import { TimelineModel } from '../../../../store/timeline/model'; import { timelineDefaults } from '../../../../store/timeline/defaults'; -import { useApolloClient } from '../../../../utils/apollo_context'; import { updateSignalStatusAction } from './actions'; import { diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/types.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/types.ts index b3e7ed75cfb99..cfcd1fe2d23fe 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/types.ts +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/types.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import ApolloClient from 'apollo-client'; +import { ApolloClient } from '@apollo/client'; import { Ecs } from '../../../../graphql/types'; import { TimelineModel } from '../../../../store/timeline/model'; @@ -42,7 +42,7 @@ export interface UpdateSignalStatusActionProps { export type SendSignalsToTimeline = () => void; export interface SendSignalToTimelineActionProps { - apolloClient?: ApolloClient<{}>; + apolloClient?: ApolloClient; createTimeline: CreateTimeline; ecsData: Ecs; updateTimelineIsLoading: ({ id, isLoading }: { id: string; isLoading: boolean }) => void; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/detection_engine.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/detection_engine.tsx index c3fb907ae83e1..575b85322dcb6 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/detection_engine.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/detection_engine.tsx @@ -10,8 +10,8 @@ import { useParams } from 'react-router-dom'; import { StickyContainer } from 'react-sticky'; import { connect, ConnectedProps } from 'react-redux'; -import { GlobalTime } from '../../containers/global_time'; -import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source'; +import { useGlobalTime } from '../../containers/global_time'; +import { useWithSource } from '../../containers/source'; import { AlertsTable } from '../../components/alerts_viewer/alerts_table'; import { FiltersGlobal } from '../../components/filters_global'; import { @@ -88,6 +88,10 @@ const DetectionEnginePageComponent: React.FC = ({ signalIndexName, ]); + const { indexPattern, contentAvailable } = useWithSource(indexToAdd); + + const { to, from, deleteQuery, setQuery } = useGlobalTime(); + if (isUserAuthenticated != null && !isUserAuthenticated && !loading) { return ( @@ -109,89 +113,81 @@ const DetectionEnginePageComponent: React.FC = ({ <> {hasEncryptionKey != null && !hasEncryptionKey && } {hasIndexWrite != null && !hasIndexWrite && } - - {({ indicesExist, indexPattern }) => { - return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? ( - - - - - - - {i18n.LAST_SIGNAL} - {': '} - {lastSignals} - - ) - } - title={i18n.PAGE_TITLE} - > - - {i18n.BUTTON_MANAGE_RULES} - - - - - {({ to, from, deleteQuery, setQuery }) => ( - <> - - - {tabName === DetectionEngineTab.signals && ( - <> - - - - - )} - {tabName === DetectionEngineTab.alerts && ( - <> - - - - )} - - )} - - - - ) : ( - - - - - ); - }} - + {contentAvailable ? ( + + + + + + + {i18n.LAST_SIGNAL} + {': '} + {lastSignals} + + ) + } + title={i18n.PAGE_TITLE} + > + + {i18n.BUTTON_MANAGE_RULES} + + + + <> + + + {tabName === DetectionEngineTab.signals && ( + <> + + + + + )} + {tabName === DetectionEngineTab.alerts && ( + <> + + + + )} + + + + ) : ( + + + + + )} ); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/index.tsx index 83dd18f0f14b7..5ccb4cf5d8372 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -/* eslint-disable react-hooks/rules-of-hooks */ +/* eslint-disable react-hooks/rules-of-hooks, complexity */ import { EuiButton, @@ -32,10 +32,7 @@ import { SiemSearchBar } from '../../../../components/search_bar'; import { WrapperPage } from '../../../../components/wrapper_page'; import { useRule } from '../../../../containers/detection_engine/rules'; -import { - indicesExistOrDataTemporarilyUnavailable, - WithSource, -} from '../../../../containers/source'; +import { useWithSource } from '../../../../containers/source'; import { SpyRoute } from '../../../../utils/route/spy_routes'; import { DetectionEngineHeaderPage } from '../../components/detection_engine_header_page'; @@ -56,7 +53,7 @@ import { StepPanel } from '../components/step_panel'; import { getStepsData, redirectToDetections } from '../helpers'; import * as ruleI18n from '../translations'; import * as i18n from './translations'; -import { GlobalTime } from '../../../../containers/global_time'; +import { useGlobalTime } from '../../../../containers/global_time'; import { signalsHistogramOptions } from '../../components/signals_histogram_panel/config'; import { inputsSelectors } from '../../../../store/inputs'; import { State } from '../../../../store'; @@ -218,6 +215,10 @@ const RuleDetailsPageComponent: FC = ({ [ruleEnabled, setRuleEnabled] ); + const { contentAvailable, indexPattern } = useWithSource(indexToAdd); + + const { to, from, deleteQuery, setQuery } = useGlobalTime(); + if (redirectToDetections(isSignalIndexExists, isAuthenticated, hasEncryptionKey)) { return ; } @@ -226,155 +227,147 @@ const RuleDetailsPageComponent: FC = ({ <> {hasIndexWrite != null && !hasIndexWrite && } {userHasNoPermissions && } - - {({ indicesExist, indexPattern }) => { - return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? ( - - {({ to, from, deleteQuery, setQuery }) => ( - - - - - - - - {detectionI18n.LAST_SIGNAL} - {': '} - {lastSignals} - , - ] - : []), - , - ]} - title={title} - > - - - - + {contentAvailable ? ( + + + + - - - - - {ruleI18n.EDIT_RULE_SETTINGS} - - - - - - - - - - {ruleError} - {tabs} - - {ruleDetailTab === RuleDetailTabs.signals && ( + + - - - - {defineRuleData != null && ( - - )} - - + {detectionI18n.LAST_SIGNAL} + {': '} + {lastSignals} + , + ] + : []), + , + ]} + title={title} + > + + + + - - - {aboutRuleData != null && ( - - )} - - + + + + + {ruleI18n.EDIT_RULE_SETTINGS} + + + + + + + + + + {ruleError} + {tabs} + + {ruleDetailTab === RuleDetailTabs.signals && ( + <> + + + + {defineRuleData != null && ( + + )} + + - - - {scheduleRuleData != null && ( - - )} - - - - - + + {aboutRuleData != null && ( + - - {ruleId != null && ( - - )} - - )} - {ruleDetailTab === RuleDetailTabs.failures && } - - - )} - - ) : ( - - + )} + + + + + + {scheduleRuleData != null && ( + + )} + + + + + + + {ruleId != null && ( + + )} + + )} + {ruleDetailTab === RuleDetailTabs.failures && } + + + ) : ( + + - - - ); - }} - + + + )} diff --git a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx index 7c5fd56bf1e91..806f6c7937077 100644 --- a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { Redirect, Route, Switch } from 'react-router-dom'; import styled from 'styled-components'; import useResizeObserver from 'use-resize-observer/polyfilled'; @@ -19,7 +19,7 @@ import { MlNetworkConditionalContainer } from '../../components/ml/conditional_l import { StatefulTimeline } from '../../components/timeline'; import { AutoSaveWarningMsg } from '../../components/timeline/auto_save_warning'; import { UseUrlState } from '../../components/url_state'; -import { WithSource, indicesExistOrDataTemporarilyUnavailable } from '../../containers/source'; +import { useWithSource } from '../../containers/source'; import { SpyRoute } from '../../utils/route/spy_routes'; import { NotFoundPage } from '../404'; import { DetectionEngineContainer } from '../detection_engine'; @@ -61,84 +61,89 @@ const calculateFlyoutHeight = ({ windowHeight: number; }): number => Math.max(0, windowHeight - globalHeaderSize); -export const HomePage: React.FC = () => { +export const HomePageComponent = () => { const { ref: measureRef, height: windowHeight = 0 } = useResizeObserver({}); - const flyoutHeight = calculateFlyoutHeight({ - globalHeaderSize: globalHeaderHeightPx, - windowHeight, - }); + const flyoutHeight = useMemo( + () => + calculateFlyoutHeight({ + globalHeaderSize: globalHeaderHeightPx, + windowHeight, + }), + [windowHeight] + ); + + const { browserFields, indexPattern, contentAvailable } = useWithSource(); return ( - +
- - {({ browserFields, indexPattern, indicesExist }) => ( - - - {indicesExistOrDataTemporarilyUnavailable(indicesExist) && ( - <> - - - - - - )} - - - - } /> - } - /> - ( - - )} - /> - ( - - )} - /> - } - /> - } /> - ( - - )} + + + {contentAvailable && ( + <> + + + - ( - - )} - /> - - - - } /> - - + + )} - + + + + + + + } + /> + ( + + )} + /> + ( + + )} + /> + + + + } /> + ( + + )} + /> + ( + + )} + /> + + + + + + + +
@@ -148,4 +153,6 @@ export const HomePage: React.FC = () => { ); }; +export const HomePage = React.memo(HomePageComponent); + HomePage.displayName = 'HomePage'; diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.test.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.test.tsx index 81c1b317d4596..1ef1edb4c4dce 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.test.tsx @@ -5,7 +5,6 @@ */ import React from 'react'; -import { IIndexPattern } from 'src/plugins/data/public'; import { MemoryRouter } from 'react-router-dom'; import useResizeObserver from 'use-resize-observer/polyfilled'; @@ -18,15 +17,6 @@ import { type } from './utils'; import { useMountAppended } from '../../../utils/use_mount_appended'; import { getHostDetailsPageFilters } from './helpers'; -jest.mock('../../../containers/source', () => ({ - indicesExistOrDataTemporarilyUnavailable: () => true, - WithSource: ({ - children, - }: { - children: (args: { indicesExist: boolean; indexPattern: IIndexPattern }) => React.ReactNode; - }) => children({ indicesExist: true, indexPattern: mockIndexPattern }), -})); - // Test will fail because we will to need to mock some core services to make the test work // For now let's forget about SiemSearchBar and QueryBar jest.mock('../../../components/search_bar', () => ({ @@ -46,7 +36,7 @@ describe('body', () => { allHosts: 'HostsQueryTabBody', uncommonProcesses: 'UncommonProcessQueryTabBody', anomalies: 'AnomaliesQueryTabBody', - events: 'EventsQueryTabBody', + events: 'Memo(EventsQueryTabBodyComponent)', alerts: 'HostAlertsQueryTabBody', }; diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx index f5efd9248029d..76b43cbcdbb4b 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx @@ -85,7 +85,6 @@ export const HostDetailsTabs = React.memo( - diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx index 8af4731e4dda4..d2d6b6cb5298e 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx @@ -25,7 +25,7 @@ import { SiemSearchBar } from '../../../components/search_bar'; import { WrapperPage } from '../../../components/wrapper_page'; import { HostOverviewByNameQuery } from '../../../containers/hosts/overview'; import { KpiHostDetailsQuery } from '../../../containers/kpi_host_details'; -import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../../containers/source'; +import { useWithSource } from '../../../containers/source'; import { LastEventIndexKey } from '../../../graphql/types'; import { useKibana } from '../../../lib/kibana'; import { convertToBuildEsQuery } from '../../../lib/keury'; @@ -74,132 +74,126 @@ const HostDetailsComponent = React.memo( }, [setAbsoluteRangeDatePicker] ); + const { contentAvailable, indexPattern } = useWithSource(); + const filterQuery = convertToBuildEsQuery({ + config: esQuery.getEsQueryConfig(kibana.services.uiSettings), + indexPattern, + queries: [query], + filters: getFilters(), + }); return ( <> - - {({ indicesExist, indexPattern }) => { - const filterQuery = convertToBuildEsQuery({ - config: esQuery.getEsQueryConfig(kibana.services.uiSettings), - indexPattern, - queries: [query], - filters: getFilters(), - }); - return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? ( - - - - - - - - } - title={detailName} - /> - - + + + + + + + } + title={detailName} + /> + + + {({ hostOverview, loading, id, inspect, refetch }) => ( + - {({ hostOverview, loading, id, inspect, refetch }) => ( - - {({ isLoadingAnomaliesData, anomaliesData }) => ( - { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }} - /> - )} - - )} - - - - - - {({ kpiHostDetails, id, inspect, loading, refetch }) => ( - ( + { + const fromTo = scoreIntervalToDateTime(score, interval); + setAbsoluteRangeDatePicker({ + id: 'global', + from: fromTo.from, + to: fromTo.to, + }); + }} /> )} - - - - - - - - - + )} + + + + + + {({ kpiHostDetails, id, inspect, loading, refetch }) => ( + - - - ) : ( - - - - - - ); - }} - + )} + + + + + + + + + + + + ) : ( + + + + + + )} diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.test.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.test.tsx index 99cf767c65e08..bbecef4e44a44 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.test.tsx @@ -8,7 +8,8 @@ import { mount } from 'enzyme'; import { cloneDeep } from 'lodash/fp'; import React from 'react'; import { Router } from 'react-router-dom'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { GraphQLRequest } from '@apollo/client'; +import { MockedProvider } from '@apollo/client/testing'; import { Filter } from '../../../../../../../src/plugins/data/common/es_query'; import '../../mock/match_media'; @@ -32,7 +33,7 @@ jest.mock('../../components/query_bar', () => ({ })); let localSource: Array<{ - request: {}; + request: GraphQLRequest; result: { data: { source: { diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx index a7aa9920b7d08..78d41f01c5d28 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx @@ -21,7 +21,7 @@ import { manageQuery } from '../../components/page/manage_query'; import { SiemSearchBar } from '../../components/search_bar'; import { WrapperPage } from '../../components/wrapper_page'; import { KpiHostsQuery } from '../../containers/kpi_hosts'; -import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source'; +import { useWithSource } from '../../containers/source'; import { LastEventIndexKey } from '../../graphql/types'; import { useKibana } from '../../lib/kibana'; import { convertToBuildEsQuery } from '../../lib/keury'; @@ -68,87 +68,83 @@ export const HostsComponent = React.memo( [setAbsoluteRangeDatePicker] ); + const { contentAvailable, indexPattern } = useWithSource(); + const filterQuery = convertToBuildEsQuery({ + config: esQuery.getEsQueryConfig(kibana.services.uiSettings), + indexPattern, + queries: [query], + filters, + }); + const tabsFilterQuery = convertToBuildEsQuery({ + config: esQuery.getEsQueryConfig(kibana.services.uiSettings), + indexPattern, + queries: [query], + filters: tabsFilters, + }); + return ( <> - - {({ indicesExist, indexPattern }) => { - const filterQuery = convertToBuildEsQuery({ - config: esQuery.getEsQueryConfig(kibana.services.uiSettings), - indexPattern, - queries: [query], - filters, - }); - const tabsFilterQuery = convertToBuildEsQuery({ - config: esQuery.getEsQueryConfig(kibana.services.uiSettings), - indexPattern, - queries: [query], - filters: tabsFilters, - }); - return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? ( - - - - - - - } - title={i18n.PAGE_TITLE} - /> - - - {({ kpiHosts, loading, id, inspect, refetch }) => ( - - )} - - - - - - - - - + + + + + + } + title={i18n.PAGE_TITLE} + /> + + + {({ kpiHosts, loading, id, inspect, refetch }) => ( + - - - ) : ( - - - - - - ); - }} - - + )} + + + + + + + + + + + + ) : ( + + + + + + )} ); diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx index 80c35e5563c1d..e788eff9f8801 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx @@ -32,9 +32,26 @@ export const HostsTabs = memo( setQuery, isInitializing, type, - indexPattern, hostsPagePath, }) => { + const narrowDateRange = useCallback( + (score: Anomaly, interval: string) => { + const fromTo = scoreIntervalToDateTime(score, interval); + setAbsoluteRangeDatePicker({ + id: 'global', + from: fromTo.from, + to: fromTo.to, + }); + }, + [setAbsoluteRangeDatePicker] + ); + const updateDateRange = useCallback( + (min: number, max: number) => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, + [setAbsoluteRangeDatePicker] + ); + const tabProps = { deleteQuery, endDate: to, @@ -43,24 +60,8 @@ export const HostsTabs = memo( setQuery, startDate: from, type, - indexPattern, - narrowDateRange: useCallback( - (score: Anomaly, interval: string) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }, - [setAbsoluteRangeDatePicker] - ), - updateDateRange: useCallback( - (min: number, max: number) => { - setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); - }, - [setAbsoluteRangeDatePicker] - ), + narrowDateRange, + updateDateRange, }; return ( diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/index.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/index.tsx index 699b1441905c3..fd50f7c24d06e 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/index.tsx @@ -10,7 +10,7 @@ import { Redirect, Route, Switch, RouteComponentProps } from 'react-router-dom'; import { HostDetails } from './details'; import { HostsTableType } from '../../store/hosts/model'; -import { GlobalTime } from '../../containers/global_time'; +import { useGlobalTime } from '../../containers/global_time'; import { SiemPageName } from '../home/types'; import { Hosts } from './hosts'; import { hostsPagePath, hostDetailsPagePath } from './types'; @@ -34,62 +34,62 @@ const getHostDetailsTabPath = (pagePath: string) => type Props = Partial> & { url: string }; -export const HostsContainer = React.memo(({ url }) => ( - - {({ to, from, setQuery, deleteQuery, isInitializing }) => ( - - ( - - )} - /> - ( - - )} - /> - } - /> - ( - - )} - /> - - )} - -)); +export const HostsContainer = React.memo(({ url }) => { + const { to, from, setQuery, deleteQuery, isInitializing } = useGlobalTime(); + + return ( + + ( + + )} + /> + ( + + )} + /> + } + /> + ( + + )} + /> + + ); +}); HostsContainer.displayName = 'HostsContainer'; diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/events_query_tab_body.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/events_query_tab_body.tsx index cb2c19c642bc4..d871c6f97e752 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/events_query_tab_body.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/events_query_tab_body.tsx @@ -47,7 +47,7 @@ export const histogramConfigs: MatrixHisrogramConfigs = { title: i18n.NAVIGATION_EVENTS_TITLE, }; -export const EventsQueryTabBody = ({ +export const EventsQueryTabBodyComponent = ({ deleteQuery, endDate, filterQuery, @@ -86,4 +86,4 @@ export const EventsQueryTabBody = ({ ); }; -EventsQueryTabBody.displayName = 'EventsQueryTabBody'; +export const EventsQueryTabBody = React.memo(EventsQueryTabBodyComponent); diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/hosts_query_tab_body.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/hosts_query_tab_body.tsx index 6c301d692d0e1..d099bcd81da65 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/hosts_query_tab_body.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/hosts_query_tab_body.tsx @@ -17,7 +17,6 @@ export const HostsQueryTabBody = ({ deleteQuery, endDate, filterQuery, - indexPattern, skip, setQuery, startDate, @@ -37,7 +36,6 @@ export const HostsQueryTabBody = ({ data={hosts} fakeTotalCount={getOr(50, 'fakeTotalCount', pageInfo)} id={id} - indexPattern={indexPattern} inspect={inspect} isInspect={isInspected} loading={loading} diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/types.ts b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/types.ts index cb5fc62b96582..be21ed91c3291 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/types.ts +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/types.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Filter, IIndexPattern } from '../../../../../../../../src/plugins/data/public'; +import { Filter } from '../../../../../../../../src/plugins/data/public'; import { NarrowDateRange } from '../../../components/ml/types'; import { ESTermQuery } from '../../../../common/typed_json'; import { InspectQuery, Refetch } from '../../../store/inputs/model'; @@ -45,7 +45,6 @@ export interface QueryTabBodyProps { export type HostsComponentsQueryProps = QueryTabBodyProps & { deleteQuery?: ({ id }: { id: string }) => void; - indexPattern: IIndexPattern; pageFilters?: Filter[]; skip: boolean; setQuery: SetQuery; diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/types.ts b/x-pack/legacy/plugins/siem/public/pages/hosts/types.ts index 408450aebebbd..cb276c0b44c00 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/types.ts +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/types.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IIndexPattern } from 'src/plugins/data/public'; import { ActionCreator } from 'typescript-fsa'; import { SiemPageName } from '../home/types'; @@ -18,7 +17,6 @@ export const hostDetailsPagePath = `${hostsPagePath}/:detailName`; export type HostsTabsProps = HostsComponentProps & { filterQuery: string; type: hostsModel.HostsType; - indexPattern: IIndexPattern; setAbsoluteRangeDatePicker: ActionCreator<{ id: InputsModelId; from: number; diff --git a/x-pack/legacy/plugins/siem/public/pages/network/index.tsx b/x-pack/legacy/plugins/siem/public/pages/network/index.tsx index 48fc1421d90bb..9e941b2c9a88c 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/index.tsx @@ -13,7 +13,7 @@ import { FlowTarget } from '../../graphql/types'; import { IPDetails } from './ip_details'; import { Network } from './network'; -import { GlobalTime } from '../../containers/global_time'; +import { useGlobalTime } from '../../containers/global_time'; import { SiemPageName } from '../home/types'; import { getNetworkRoutePath } from './navigation'; import { NetworkRouteType } from './navigation/types'; @@ -33,67 +33,64 @@ const NetworkContainerComponent: React.FC = () => { () => getNetworkRoutePath(networkPagePath, capabilitiesFetched, userHasMlUserPermissions), [capabilitiesFetched, userHasMlUserPermissions] ); + const { to, from, setQuery, deleteQuery, isInitializing } = useGlobalTime(); return ( - - {({ to, from, setQuery, deleteQuery, isInitializing }) => ( - - ( - - )} + + ( + - ( - - )} + )} + /> + ( + - ( - - )} + )} + /> + ( + - ( - - )} - /> - - )} - + )} + /> + ( + + )} + /> + ); }; diff --git a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/__snapshots__/index.test.tsx.snap index e7598ef03d786..1f74f026542a1 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/__snapshots__/index.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/__snapshots__/index.test.tsx.snap @@ -1,13 +1,60 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Ip Details it matches the snapshot 1`] = ` - - - - - - + `; diff --git a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.test.tsx index 02132d790796c..908d5bf26212d 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.test.tsx @@ -8,7 +8,8 @@ import { shallow } from 'enzyme'; import { cloneDeep } from 'lodash/fp'; import React from 'react'; import { Router } from 'react-router-dom'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { GraphQLRequest } from '@apollo/client'; +import { MockedProvider } from '@apollo/client/testing'; import { ActionCreator } from 'typescript-fsa'; import '../../../mock/match_media'; @@ -19,6 +20,7 @@ import { apolloClientObservable, mockGlobalState, TestProviders } from '../../.. import { useMountAppended } from '../../../utils/use_mount_appended'; import { createStore, State } from '../../../store'; import { InputsModelId } from '../../../store/inputs/constants'; +// import { useUiSetting$ } from '../../lib/kibana'; import { IPDetailsComponent, IPDetails } from './index'; @@ -35,9 +37,47 @@ jest.mock('../../../components/search_bar', () => ({ jest.mock('../../../components/query_bar', () => ({ QueryBar: () => null, })); +jest.mock('../../../containers/source', () => ({ + useWithSource: () => ({ + contentAvailable: true, + }), +})); + +jest.mock('../../../../../../../../src/plugins/kibana_react/public/context/context', () => ({ + ...jest.requireActual('../../../../../../../../src/plugins/kibana_react/public/context/context'), + useKibana: () => ({ + services: { + http: { + basePath: { + get: () => '', + }, + }, + docLinks: { + links: { + siem: { + gettingStarted: '', + }, + }, + }, + uiSettings: { + get: () => '', + }, + }, + }), +})); + +jest.mock( + '../../../../../../../../src/plugins/kibana_react/public/ui_settings/use_ui_setting', + () => ({ + ...jest.requireActual( + '../../../../../../../../src/plugins/kibana_react/public/ui_settings/use_ui_setting' + ), + useUiSetting$: () => [], + }) +); let localSource: Array<{ - request: {}; + request: GraphQLRequest; result: { data: { source: { @@ -122,16 +162,31 @@ describe('Ip Details', () => { }); test('it renders', () => { - const wrapper = shallow(); - expect(wrapper.find('[data-test-subj="ip-details-page"]').exists()).toBe(true); + const wrapper = shallow( + + + + ); + + expect( + wrapper + .find('IPDetailsComponent') + .dive() + .find('[data-test-subj="ip-details-page"]') + .exists() + ).toBe(true); }); test('it matches the snapshot', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); + const wrapper = shallow( + + + + ); + expect(wrapper.find('IPDetailsComponent')).toMatchSnapshot(); }); - test('it renders ipv6 headline', async () => { + test('it renders ipv6 headline', () => { localSource[0].result.data.source.status.indicesExist = true; const ip = 'fe80--24ce-f7ff-fede-a571'; const wrapper = mount( @@ -143,9 +198,6 @@ describe('Ip Details', () => { ); - // Why => https://github.com/apollographql/react-apollo/issues/1711 - await new Promise(resolve => setTimeout(resolve)); - wrapper.update(); expect( wrapper .find('[data-test-subj="ip-details-headline"] [data-test-subj="header-page-title"]') diff --git a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx index e796eaca0cd28..160f9343caf75 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx @@ -22,7 +22,7 @@ import { IpOverview } from '../../../components/page/network/ip_overview'; import { SiemSearchBar } from '../../../components/search_bar'; import { WrapperPage } from '../../../components/wrapper_page'; import { IpOverviewQuery } from '../../../containers/ip_overview'; -import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../../containers/source'; +import { useWithSource } from '../../../containers/source'; import { FlowTargetSourceDest, LastEventIndexKey } from '../../../graphql/types'; import { useKibana } from '../../../lib/kibana'; import { decodeIpv6 } from '../../../lib/helpers'; @@ -76,202 +76,199 @@ export const IPDetailsComponent: React.FC - - {({ indicesExist, indexPattern }) => { - const ip = decodeIpv6(detailName); - const filterQuery = convertToBuildEsQuery({ - config: esQuery.getEsQueryConfig(kibana.services.uiSettings), - indexPattern, - queries: [query], - filters, - }); - - return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? ( - - - - - - - } - title={ip} - > - - + const { indexPattern, contentAvailable } = useWithSource(); + const ip = decodeIpv6(detailName); + const filterQuery = convertToBuildEsQuery({ + config: esQuery.getEsQueryConfig(kibana.services.uiSettings), + indexPattern, + queries: [query], + filters, + }); - + {contentAvailable ? ( + + + + + + + } + title={ip} + > + + + + + {({ id, inspect, ipOverviewData, loading, refetch }) => ( + - {({ id, inspect, ipOverviewData, loading, refetch }) => ( - - {({ isLoadingAnomaliesData, anomaliesData }) => ( - - )} - - )} - - - - - - - ( + - - - - - - - - - - - - - - - - - - + )} + + )} + - + - + + + - - - + + + - + - + + + - - - + - - - ) : ( - - - - - - ); - }} - + + + + + + + + + + + + + + + + + + + + + ) : ( + + + + + + )} - + ); }; IPDetailsComponent.displayName = 'IPDetailsComponent'; @@ -291,7 +288,7 @@ const mapDispatchToProps = { setIpDetailsTablesActivePageToZero: dispatchIpDetailsTablesActivePageToZero, }; -export const connector = connect(makeMapStateToProps, mapDispatchToProps); +const connector = connect(makeMapStateToProps, mapDispatchToProps); type PropsFromRedux = ConnectedProps; diff --git a/x-pack/legacy/plugins/siem/public/pages/network/network.test.tsx b/x-pack/legacy/plugins/siem/public/pages/network/network.test.tsx index 797fef1586518..41c967ffe9874 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/network.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/network.test.tsx @@ -8,7 +8,8 @@ import { mount } from 'enzyme'; import { cloneDeep } from 'lodash/fp'; import React from 'react'; import { Router } from 'react-router-dom'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { GraphQLRequest } from '@apollo/client'; +import { MockedProvider } from '@apollo/client/testing'; import '../../mock/match_media'; import { Filter } from '../../../../../../../src/plugins/data/common/es_query'; @@ -29,7 +30,7 @@ jest.mock('../../components/query_bar', () => ({ })); let localSource: Array<{ - request: {}; + request: GraphQLRequest; result: { data: { source: { diff --git a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx index 9b1ee76e1d376..c71f361e5c9f3 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx @@ -21,7 +21,7 @@ import { KpiNetworkComponent } from '../../components/page/network'; import { SiemSearchBar } from '../../components/search_bar'; import { WrapperPage } from '../../components/wrapper_page'; import { KpiNetworkQuery } from '../../containers/kpi_network'; -import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source'; +import { useWithSource } from '../../containers/source'; import { LastEventIndexKey } from '../../graphql/types'; import { useKibana } from '../../lib/kibana'; import { convertToBuildEsQuery } from '../../lib/keury'; @@ -68,103 +68,101 @@ const NetworkComponent = React.memo( [setAbsoluteRangeDatePicker] ); + const { contentAvailable, indexPattern } = useWithSource(); + + const filterQuery = convertToBuildEsQuery({ + config: esQuery.getEsQueryConfig(kibana.services.uiSettings), + indexPattern, + queries: [query], + filters, + }); + const tabsFilterQuery = convertToBuildEsQuery({ + config: esQuery.getEsQueryConfig(kibana.services.uiSettings), + indexPattern, + queries: [query], + filters: tabsFilters, + }); + return ( <> - - {({ indicesExist, indexPattern }) => { - const filterQuery = convertToBuildEsQuery({ - config: esQuery.getEsQueryConfig(kibana.services.uiSettings), - indexPattern, - queries: [query], - filters, - }); - const tabsFilterQuery = convertToBuildEsQuery({ - config: esQuery.getEsQueryConfig(kibana.services.uiSettings), - indexPattern, - queries: [query], - filters: tabsFilters, - }); - - return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? ( - - - - - - - } - title={i18n.PAGE_TITLE} - /> - - + + + + + + } + title={i18n.PAGE_TITLE} + /> + + + + + + + {({ kpiNetwork, loading, id, inspect, refetch }) => ( + + )} + + {capabilitiesFetched && !isInitializing ? ( + <> - - {({ kpiNetwork, loading, id, inspect, refetch }) => ( - - )} - - - {capabilitiesFetched && !isInitializing ? ( - <> - - - - - - - - - ) : ( - - )} + - - - ) : ( - - - - - ); - }} - + + + + ) : ( + + )} + + + + + ) : ( + + + + + )} diff --git a/x-pack/legacy/plugins/siem/public/pages/overview/event_counts/index.tsx b/x-pack/legacy/plugins/siem/public/pages/overview/event_counts/index.tsx index 0fc37935b6062..a6725231ccf62 100644 --- a/x-pack/legacy/plugins/siem/public/pages/overview/event_counts/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/overview/event_counts/index.tsx @@ -53,17 +53,26 @@ const EventCountsComponent: React.FC = ({ }) => { const kibana = useKibana(); + const hostFilterQuery = convertToBuildEsQuery({ + config: esQuery.getEsQueryConfig(kibana.services.uiSettings), + indexPattern, + queries: [query], + filters: [...filters, ...filterHostData], + }); + + const networkFilterQuery = convertToBuildEsQuery({ + config: esQuery.getEsQueryConfig(kibana.services.uiSettings), + indexPattern, + queries: [query], + filters: [...filters, ...filterNetworkData], + }); + return ( @@ -74,12 +83,7 @@ const EventCountsComponent: React.FC = ({ diff --git a/x-pack/legacy/plugins/siem/public/pages/overview/index.tsx b/x-pack/legacy/plugins/siem/public/pages/overview/index.tsx index 65b401f00a86e..2b8e61dec301c 100644 --- a/x-pack/legacy/plugins/siem/public/pages/overview/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/overview/index.tsx @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { memo } from 'react'; +import { memo } from 'react'; import { StatefulOverview } from './overview'; -export const Overview = memo(() => ); +export const Overview = memo(StatefulOverview); Overview.displayName = 'Overview'; diff --git a/x-pack/legacy/plugins/siem/public/pages/overview/overview.test.tsx b/x-pack/legacy/plugins/siem/public/pages/overview/overview.test.tsx index b20cd84295566..aa523db32bde2 100644 --- a/x-pack/legacy/plugins/siem/public/pages/overview/overview.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/overview/overview.test.tsx @@ -7,7 +7,8 @@ import { mount } from 'enzyme'; import { cloneDeep } from 'lodash/fp'; import React from 'react'; -import { MockedProvider } from 'react-apollo/test-utils'; +import { GraphQLRequest } from '@apollo/client'; +import { MockedProvider } from '@apollo/client/testing'; import { MemoryRouter } from 'react-router-dom'; import '../../mock/match_media'; @@ -34,7 +35,7 @@ jest.mock('../../components/query_bar', () => ({ })); let localSource: Array<{ - request: {}; + request: GraphQLRequest; result: { data: { source: { diff --git a/x-pack/legacy/plugins/siem/public/pages/overview/overview.tsx b/x-pack/legacy/plugins/siem/public/pages/overview/overview.tsx index 2db49e60193fc..83d36e043b6e0 100644 --- a/x-pack/legacy/plugins/siem/public/pages/overview/overview.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/overview/overview.tsx @@ -15,8 +15,8 @@ import { AlertsByCategory } from './alerts_by_category'; import { FiltersGlobal } from '../../components/filters_global'; import { SiemSearchBar } from '../../components/search_bar'; import { WrapperPage } from '../../components/wrapper_page'; -import { GlobalTime } from '../../containers/global_time'; -import { WithSource, indicesExistOrDataTemporarilyUnavailable } from '../../containers/source'; +import { useGlobalTime } from '../../containers/global_time'; +import { useWithSource } from '../../containers/source'; import { EventsByDataset } from './events_by_dataset'; import { EventCounts } from './event_counts'; import { OverviewEmpty } from './overview_empty'; @@ -37,89 +37,86 @@ const OverviewComponent: React.FC = ({ filters = NO_FILTERS, query = DEFAULT_QUERY, setAbsoluteRangeDatePicker, -}) => ( - <> - - {({ indicesExist, indexPattern }) => - indicesExistOrDataTemporarilyUnavailable(indicesExist) ? ( - - - - - - - - - - - - - - {({ from, deleteQuery, setQuery, to }) => ( - - - - - - - - - - - - - - - - - - - )} - - - - - - ) : ( - - ) - } - - - - -); +}) => { + const { indexPattern, contentAvailable } = useWithSource(); + const { from, deleteQuery, setQuery, to } = useGlobalTime(); + + return ( + <> + {contentAvailable ? ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) : ( + + )} + + + + ); +}; const makeMapStateToProps = () => { const getGlobalFiltersQuerySelector = inputsSelectors.globalFiltersQuerySelector(); diff --git a/x-pack/legacy/plugins/siem/public/pages/overview/sidebar/sidebar.tsx b/x-pack/legacy/plugins/siem/public/pages/overview/sidebar/sidebar.tsx index d3b85afe62a2a..ac09a3a72dc64 100644 --- a/x-pack/legacy/plugins/siem/public/pages/overview/sidebar/sidebar.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/overview/sidebar/sidebar.tsx @@ -14,7 +14,6 @@ import { StatefulRecentTimelines } from '../../../components/recent_timelines'; import { StatefulNewsFeed } from '../../../components/news_feed'; import { FilterMode } from '../../../components/recent_timelines/types'; import { SidebarHeader } from '../../../components/sidebar_header'; -import { useApolloClient } from '../../../utils/apollo_context'; import * as i18n from '../translations'; @@ -26,7 +25,6 @@ export const Sidebar = React.memo<{ filterBy: FilterMode; setFilterBy: (filterBy: FilterMode) => void; }>(({ filterBy, setFilterBy }) => { - const apolloClient = useApolloClient(); const RecentTimelinesFilters = useMemo( () => , [filterBy, setFilterBy] @@ -36,7 +34,7 @@ export const Sidebar = React.memo<{ {RecentTimelinesFilters} - + diff --git a/x-pack/legacy/plugins/siem/public/pages/timelines/index.tsx b/x-pack/legacy/plugins/siem/public/pages/timelines/index.tsx index aa5c891de3628..7102b64535617 100644 --- a/x-pack/legacy/plugins/siem/public/pages/timelines/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/timelines/index.tsx @@ -5,12 +5,39 @@ */ import React from 'react'; -import { ApolloConsumer } from 'react-apollo'; +import styled from 'styled-components'; -import { TimelinesPage } from './timelines_page'; +import { HeaderPage } from '../../components/header_page'; +import { StatefulOpenTimeline } from '../../components/open_timeline'; +import { WrapperPage } from '../../components/wrapper_page'; +import { SpyRoute } from '../../utils/route/spy_routes'; +import * as i18n from './translations'; -export const Timelines = React.memo(() => ( - {client => } -)); +const TimelinesContainer = styled.div` + width: 100%; +`; +TimelinesContainer.displayName = 'TimelinesContainer'; -Timelines.displayName = 'Timelines'; +export const DEFAULT_SEARCH_RESULTS_PER_PAGE = 10; + +export const TimelinesPage = () => ( + <> + + + + + + + + + + +); + +TimelinesPage.displayName = 'TimelinesPage'; + +export const Timelines = React.memo(TimelinesPage); diff --git a/x-pack/legacy/plugins/siem/public/pages/timelines/timelines_page.tsx b/x-pack/legacy/plugins/siem/public/pages/timelines/timelines_page.tsx deleted file mode 100644 index 86f702a8ad8a4..0000000000000 --- a/x-pack/legacy/plugins/siem/public/pages/timelines/timelines_page.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import ApolloClient from 'apollo-client'; -import React from 'react'; -import styled from 'styled-components'; - -import { HeaderPage } from '../../components/header_page'; -import { StatefulOpenTimeline } from '../../components/open_timeline'; -import { WrapperPage } from '../../components/wrapper_page'; -import { SpyRoute } from '../../utils/route/spy_routes'; -import * as i18n from './translations'; - -const TimelinesContainer = styled.div` - width: 100%; -`; - -interface TimelinesProps { - apolloClient: ApolloClient; -} - -type OwnProps = TimelinesProps; - -export const DEFAULT_SEARCH_RESULTS_PER_PAGE = 10; - -const TimelinesPageComponent: React.FC = ({ apolloClient }) => ( - <> - - - - - - - - - - -); - -export const TimelinesPage = React.memo(TimelinesPageComponent); diff --git a/x-pack/legacy/plugins/siem/public/store/timeline/epic_favorite.ts b/x-pack/legacy/plugins/siem/public/store/timeline/epic_favorite.ts index 4d1b73aa70a6e..52b2b8ec0c185 100644 --- a/x-pack/legacy/plugins/siem/public/store/timeline/epic_favorite.ts +++ b/x-pack/legacy/plugins/siem/public/store/timeline/epic_favorite.ts @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { NormalizedCacheObject } from 'apollo-cache-inmemory'; -import { ApolloClient } from 'apollo-client'; +import { ApolloClient, NormalizedCacheObject } from '@apollo/client'; import { get } from 'lodash/fp'; import { Action } from 'redux'; import { Epic } from 'redux-observable'; diff --git a/x-pack/legacy/plugins/siem/public/store/timeline/epic_note.ts b/x-pack/legacy/plugins/siem/public/store/timeline/epic_note.ts index e5a712fe2c666..4dcdcbd33016b 100644 --- a/x-pack/legacy/plugins/siem/public/store/timeline/epic_note.ts +++ b/x-pack/legacy/plugins/siem/public/store/timeline/epic_note.ts @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ApolloClient } from 'apollo-client'; -import { NormalizedCacheObject } from 'apollo-cache-inmemory'; +import { ApolloClient, NormalizedCacheObject } from '@apollo/client'; import { get } from 'lodash/fp'; import { Action } from 'redux'; import { Epic } from 'redux-observable'; diff --git a/x-pack/legacy/plugins/siem/public/store/timeline/epic_pinned_event.ts b/x-pack/legacy/plugins/siem/public/store/timeline/epic_pinned_event.ts index 2260999a91e7b..b73d1e3ad7fef 100644 --- a/x-pack/legacy/plugins/siem/public/store/timeline/epic_pinned_event.ts +++ b/x-pack/legacy/plugins/siem/public/store/timeline/epic_pinned_event.ts @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { NormalizedCacheObject } from 'apollo-cache-inmemory'; -import { ApolloClient } from 'apollo-client'; +import { ApolloClient, NormalizedCacheObject } from '@apollo/client'; import { get, omit } from 'lodash/fp'; import { Action } from 'redux'; import { Epic } from 'redux-observable'; diff --git a/x-pack/legacy/plugins/siem/public/utils/apollo_context.ts b/x-pack/legacy/plugins/siem/public/utils/apollo_context.ts deleted file mode 100644 index f0c5e7e917e13..0000000000000 --- a/x-pack/legacy/plugins/siem/public/utils/apollo_context.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { ApolloClient } from 'apollo-client'; -import { createContext, useContext } from 'react'; - -/** - * This is a temporary provider and hook for use with hooks until react-apollo - * has upgraded to the new-style `createContext` api. - */ - -export const ApolloClientContext = createContext | undefined>(undefined); - -export const useApolloClient = () => { - return useContext(ApolloClientContext); -}; diff --git a/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx b/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx index ddee2359b28ba..0d980c0bf7d66 100644 --- a/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx +++ b/x-pack/legacy/plugins/siem/public/utils/route/spy_routes.tsx @@ -81,7 +81,8 @@ export const SpyRouteComponent = memo( } }, [pathname, search, pageName, detailName, tabName, flowTarget, state]); return null; - } + }, + deepEqual ); export const SpyRoute = withRouter(SpyRouteComponent); diff --git a/x-pack/legacy/plugins/siem/scripts/combined_schema.ts b/x-pack/legacy/plugins/siem/scripts/combined_schema.ts index 625eb3a4a4755..71eaf8490f7e2 100644 --- a/x-pack/legacy/plugins/siem/scripts/combined_schema.ts +++ b/x-pack/legacy/plugins/siem/scripts/combined_schema.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { buildSchemaFromTypeDefinitions } from 'graphql-tools'; +import { buildSchemaFromTypeDefinitions } from '@kamilkisiela/graphql-tools'; import { schemas as serverSchemas } from '../server/graphql'; diff --git a/x-pack/legacy/plugins/siem/scripts/generate_types_from_graphql.js b/x-pack/legacy/plugins/siem/scripts/generate_types_from_graphql.js index 36674fec73e09..e6f5f2388a281 100644 --- a/x-pack/legacy/plugins/siem/scripts/generate_types_from_graphql.js +++ b/x-pack/legacy/plugins/siem/scripts/generate_types_from_graphql.js @@ -4,138 +4,171 @@ * you may not use this file except in compliance with the Elastic License. */ +/* eslint-disable import/no-extraneous-dependencies */ + require('../../../../../src/setup_node_env'); -const { join, resolve } = require('path'); -// eslint-disable-next-line import/no-extraneous-dependencies, import/no-unresolved -const { generate } = require('graphql-code-generator'); +const path = require('path'); +const { codegen } = require('@graphql-codegen/core'); +const { loadDocuments } = require('@graphql-toolkit/core'); +const { GraphQLFileLoader } = require('@graphql-toolkit/graphql-file-loader'); +const { CodeFileLoader } = require('@graphql-toolkit/code-file-loader'); const GRAPHQL_GLOBS = [ - join('public', 'containers', '**', '*.gql_query.ts{,x}'), - join('common', 'graphql', '**', '*.gql_query.ts{,x}'), + path.join('public', 'containers', '**', '*.gql_query.ts'), + path.join('common', 'graphql', '**', '*.gql_query.ts'), ]; -const OUTPUT_INTROSPECTION_PATH = resolve('public', 'graphql', 'introspection.json'); -const OUTPUT_CLIENT_TYPES_PATH = resolve('public', 'graphql', 'types.ts'); -const OUTPUT_SERVER_TYPES_PATH = resolve('server', 'graphql', 'types.ts'); -const SCHEMA_PATH = resolve(__dirname, 'combined_schema.ts'); +const OUTPUT_CLIENT_TYPES_PATH = path.resolve('public', 'graphql', 'types.tsx'); +const OUTPUT_SERVER_TYPES_PATH = path.resolve('server', 'graphql', 'types.ts'); +const combinedSchema = require('./combined_schema'); + +const { printSchema, parse } = require('graphql'); +const fs = require('fs'); +const addPlugin = require('@graphql-codegen/add'); +const typescriptPlugin = require('@graphql-codegen/typescript'); +const typescriptOperationsPlugin = require('@graphql-codegen/typescript-operations'); +const typescriptResolversPlugin = require('@graphql-codegen/typescript-resolvers'); +const typescriptCompatibilityPlugin = require('@graphql-codegen/typescript-compatibility'); +const typescriptReactApolloPlugin = require('@graphql-codegen/typescript-react-apollo'); async function main() { - await generate( - { - schema: SCHEMA_PATH, - overwrite: true, - generates: { - [OUTPUT_INTROSPECTION_PATH]: { - documents: GRAPHQL_GLOBS, - primitives: { - String: 'string', - Int: 'number', - Float: 'number', - Boolean: 'boolean', - ID: 'string', - }, - config: { - namingConvention: { - typeNames: 'change-case#pascalCase', - enumValues: 'keep', - }, - contextType: 'SiemContext', - scalars: { - ToStringArray: 'string[] | string', - ToNumberArray: 'number[] | number', - ToDateArray: 'string[] | string', - ToBooleanArray: 'boolean[] | boolean', - Date: 'string', - }, - }, - plugins: ['introspection'], - }, - [OUTPUT_CLIENT_TYPES_PATH]: { - documents: GRAPHQL_GLOBS, - primitives: { - String: 'string', - Int: 'number', - Float: 'number', - Boolean: 'boolean', - ID: 'string', - }, - config: { - avoidOptionals: false, - namingConvention: { - typeNames: 'change-case#pascalCase', - enumValues: 'keep', - }, - contextType: 'SiemContext', - scalars: { - ToStringArray: 'string[]', - ToNumberArray: 'number[]', - ToDateArray: 'string[]', - ToBooleanArray: 'boolean[]', - Date: 'string', - }, - }, - plugins: [ - { - add: `/* tslint:disable */ - /* eslint-disable */ - /* - * 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. - */ - `, - }, - 'typescript-common', - 'typescript-server', - 'typescript-client', - ], - }, - [OUTPUT_SERVER_TYPES_PATH]: { - primitives: { - String: 'string', - Int: 'number', - Float: 'number', - Boolean: 'boolean', - ID: 'string', - }, - config: { - avoidOptionals: false, - namingConvention: { - typeNames: 'change-case#pascalCase', - enumValues: 'keep', - }, - contextType: 'SiemContext', - scalars: { - ToStringArray: 'string[] | string', - ToNumberArray: 'number[] | number', - ToDateArray: 'string[] | string', - ToBooleanArray: 'boolean[] | boolean', - Date: 'string', - }, - }, - plugins: [ - { - add: ` - /* tslint:disable */ - /* eslint-disable */ - /* - * 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. - */ + const documents = await loadDocuments(GRAPHQL_GLOBS, { + loaders: [new GraphQLFileLoader(), new CodeFileLoader()], + }); - import { SiemContext } from '../lib/types'; - `, - }, - 'typescript-common', - 'typescript-server', - 'typescript-resolvers', - ], + const client = await codegen({ + schema: parse(printSchema(combinedSchema.default)), + documents, + overwrite: true, + filename: OUTPUT_CLIENT_TYPES_PATH, + primitives: { + String: 'string', + Int: 'number', + Float: 'number', + Boolean: 'boolean', + ID: 'string', + }, + config: { + dedupeOperationSuffix: false, + preResolveTypes: true, + avoidOptionals: false, + namingConvention: { + typeNames: 'change-case#pascalCase', + enumValues: 'keep', + }, + contextType: 'SiemContext', + scalars: { + ToStringArray: 'string[]', + ToNumberArray: 'number[]', + ToDateArray: 'string[]', + ToBooleanArray: 'boolean[]', + Date: 'string', + }, + }, + plugins: [ + { + add: [ + '/*', + ' * 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.', + ' */', + '', + '/* tslint:disable */', + '/* eslint-disable */', + '', + ].join('\n'), + }, + { + typescript: {}, + }, + { + 'typescript-operations': {}, + }, + { + 'typescript-react-apollo': { + apolloReactComponentsImportFrom: '@apollo/react-components', + reactApolloVersion: 3, + withHooks: true, + withHOC: false, }, }, + { + 'typescript-compatibility': {}, + }, + ], + pluginMap: { + add: addPlugin, + typescript: typescriptPlugin, + 'typescript-operations': typescriptOperationsPlugin, + 'typescript-react-apollo': typescriptReactApolloPlugin, + 'typescript-compatibility': typescriptCompatibilityPlugin, + }, + }); + + const server = await codegen({ + schema: parse(printSchema(combinedSchema.default)), + documents, + overwrite: true, + filename: OUTPUT_SERVER_TYPES_PATH, + primitives: { + String: 'string', + Int: 'number', + Float: 'number', + Boolean: 'boolean', + ID: 'string', + }, + config: { + declarationKind: 'interface', + useIndexSignature: true, + skipTypename: true, + avoidOptionals: false, + preResolveTypes: true, + namingConvention: { + typeNames: 'change-case#pascalCase', + enumValues: 'keep', + }, + contextType: 'SiemContext', + scalars: { + ToStringArray: 'string[] | string', + ToNumberArray: 'number[] | number', + ToDateArray: 'string[] | string', + ToBooleanArray: 'boolean[] | boolean', + Date: 'string', + }, }, - true - ); + plugins: [ + { + add: [ + '/*', + ' * 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.', + '*/', + '', + '/* tslint:disable */', + '/* eslint-disable */', + '', + `import { SiemContext } from '../lib/types';`, + '', + ].join('\n'), + }, + { + typescript: {}, + }, + { + 'typescript-resolvers': {}, + }, + ], + pluginMap: { + add: addPlugin, + typescript: typescriptPlugin, + 'typescript-resolvers': typescriptResolversPlugin, + }, + }); + + fs.writeFileSync(OUTPUT_CLIENT_TYPES_PATH, client); + fs.writeFileSync(OUTPUT_SERVER_TYPES_PATH, server); } if (require.main === module) { diff --git a/x-pack/legacy/plugins/siem/server/graphql/authentications/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/authentications/resolvers.ts index b66ccd9a111b7..4bb626285e3ce 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/authentications/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/authentications/resolvers.ts @@ -6,14 +6,7 @@ import { SourceResolvers } from '../../graphql/types'; import { Authentications } from '../../lib/authentications'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; import { createOptionsPaginated } from '../../utils/build_query/create_options'; -import { QuerySourceResolver } from '../sources/resolvers'; - -type QueryAuthenticationsResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; export interface AuthenticationsResolversDeps { authentications: Authentications; @@ -23,7 +16,7 @@ export const createAuthenticationsResolvers = ( libs: AuthenticationsResolversDeps ): { Source: { - Authentications: QueryAuthenticationsResolver; + Authentications: SourceResolvers['Authentications']; }; } => ({ Source: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/authentications/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/authentications/schema.gql.ts index 20935ce9ed03f..f297244762b1e 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/authentications/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/authentications/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const authenticationsSchema = gql` type LastSourceHost { diff --git a/x-pack/legacy/plugins/siem/server/graphql/ecs/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/ecs/schema.gql.ts index f897236b3470e..da7b1eda7935a 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/ecs/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/ecs/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const ecsSchema = gql` scalar ToStringArray diff --git a/x-pack/legacy/plugins/siem/server/graphql/events/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/events/resolvers.ts index a9ef6bc682c84..7a57c6f3e3776 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/events/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/events/resolvers.ts @@ -7,37 +7,21 @@ import { GraphQLScalarType, Kind } from 'graphql'; import { Events } from '../../lib/events'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; import { createOptions } from '../../utils/build_query/create_options'; -import { QuerySourceResolver } from '../sources/resolvers'; import { SourceResolvers } from '../types'; import { LastEventTimeRequestOptions } from '../../lib/events/types'; -type QueryTimelineResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - -type QueryTimelineDetailsResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - -type QueryLastEventTimeResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - export interface EventsResolversDeps { events: Events; } + export const createEventsResolvers = ( libs: EventsResolversDeps ): { Source: { - Timeline: QueryTimelineResolver; - TimelineDetails: QueryTimelineDetailsResolver; - LastEventTime: QueryLastEventTimeResolver; + Timeline: SourceResolvers['Timeline']; + TimelineDetails: SourceResolvers['TimelineDetails']; + LastEventTime: SourceResolvers['LastEventTime']; }; } => ({ Source: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/events/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/events/schema.gql.ts index 3b71977bc0d47..ffef0d218eb21 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/events/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/events/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const eventsSchema = gql` scalar EsValue diff --git a/x-pack/legacy/plugins/siem/server/graphql/hosts/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/hosts/resolvers.ts index 65403c4b31261..9d86cb3ffae48 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/hosts/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/hosts/resolvers.ts @@ -7,7 +7,6 @@ import { getOr } from 'lodash/fp'; import { SourceResolvers } from '../../graphql/types'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; import { Hosts, HostOverviewRequestOptions, @@ -16,22 +15,6 @@ import { } from '../../lib/hosts'; import { getFields } from '../../utils/build_query'; import { createOptionsPaginated } from '../../utils/build_query/create_options'; -import { QuerySourceResolver } from '../sources/resolvers'; - -type QueryHostsResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - -type QueryHostOverviewResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - -type QueryHostFirstLastSeenResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; export interface HostsResolversDeps { hosts: Hosts; @@ -41,9 +24,9 @@ export const createHostsResolvers = ( libs: HostsResolversDeps ): { Source: { - Hosts: QueryHostsResolver; - HostOverview: QueryHostOverviewResolver; - HostFirstLastSeen: QueryHostFirstLastSeenResolver; + Hosts: SourceResolvers['Hosts']; + HostOverview: SourceResolvers['HostOverview']; + HostFirstLastSeen: SourceResolvers['HostFirstLastSeen']; }; } => ({ Source: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/hosts/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/hosts/schema.gql.ts index d813a08cad6db..763a83f82a1d8 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/hosts/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/hosts/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const hostsSchema = gql` type OsFields { diff --git a/x-pack/legacy/plugins/siem/server/graphql/ip_details/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/ip_details/resolvers.ts index d0e84026de473..ab3f0f67dcef2 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/ip_details/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/ip_details/resolvers.ts @@ -5,20 +5,8 @@ */ import { SourceResolvers } from '../../graphql/types'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; import { IpDetails, UsersRequestOptions } from '../../lib/ip_details'; import { createOptions, createOptionsPaginated } from '../../utils/build_query/create_options'; -import { QuerySourceResolver } from '../sources/resolvers'; - -export type QueryIpOverviewResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - -export type QueryUsersResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; export interface IDetailsResolversDeps { ipDetails: IpDetails; @@ -28,8 +16,8 @@ export const createIpDetailsResolvers = ( libs: IDetailsResolversDeps ): { Source: { - IpOverview: QueryIpOverviewResolver; - Users: QueryUsersResolver; + IpOverview: SourceResolvers['IpOverview']; + Users: SourceResolvers['Users']; }; } => ({ Source: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/ip_details/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/ip_details/schema.gql.ts index 4684449c1b80f..adfe0601b3584 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/ip_details/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/ip_details/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; const ipOverviewSchema = gql` type AutonomousSystemOrganization { diff --git a/x-pack/legacy/plugins/siem/server/graphql/kpi_hosts/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/kpi_hosts/resolvers.ts index 6708bdcd55d62..5579a877bd3a7 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/kpi_hosts/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/kpi_hosts/resolvers.ts @@ -5,20 +5,8 @@ */ import { SourceResolvers } from '../../graphql/types'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; import { KpiHosts } from '../../lib/kpi_hosts'; import { createOptions } from '../../utils/build_query/create_options'; -import { QuerySourceResolver } from '../sources/resolvers'; - -export type QueryKpiHostsResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - -export type QueryKpiHostDetailsResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; export interface KpiHostsResolversDeps { kpiHosts: KpiHosts; @@ -28,8 +16,8 @@ export const createKpiHostsResolvers = ( libs: KpiHostsResolversDeps ): { Source: { - KpiHosts: QueryKpiHostsResolver; - KpiHostDetails: QueryKpiHostDetailsResolver; + KpiHosts: SourceResolvers['KpiHosts']; + KpiHostDetails: SourceResolvers['KpiHostDetails']; }; } => ({ Source: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/kpi_hosts/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/kpi_hosts/schema.gql.ts index 49c988436e977..f73346432b89f 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/kpi_hosts/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/kpi_hosts/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const kpiHostsSchema = gql` type KpiHostHistogramData { diff --git a/x-pack/legacy/plugins/siem/server/graphql/kpi_network/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/kpi_network/resolvers.ts index b587d8c4ac726..0cb14933fd887 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/kpi_network/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/kpi_network/resolvers.ts @@ -5,15 +5,8 @@ */ import { SourceResolvers } from '../../graphql/types'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; import { KpiNetwork } from '../../lib/kpi_network'; import { createOptions } from '../../utils/build_query/create_options'; -import { QuerySourceResolver } from '../sources/resolvers'; - -export type QueryKipNetworkResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; export interface KpiNetworkResolversDeps { kpiNetwork: KpiNetwork; @@ -23,7 +16,7 @@ export const createKpiNetworkResolvers = ( libs: KpiNetworkResolversDeps ): { Source: { - KpiNetwork: QueryKipNetworkResolver; + KpiNetwork: SourceResolvers['KpiNetwork']; }; } => ({ Source: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/kpi_network/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/kpi_network/schema.gql.ts index 830240a83bd91..9be8cc806a4c6 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/kpi_network/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/kpi_network/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const kpiNetworkSchema = gql` type KpiNetworkHistogramData { diff --git a/x-pack/legacy/plugins/siem/server/graphql/matrix_histogram/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/matrix_histogram/resolvers.ts index 35cebe4777dcf..c8375e53c5d61 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/matrix_histogram/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/matrix_histogram/resolvers.ts @@ -5,25 +5,18 @@ */ import { MatrixHistogram } from '../../lib/matrix_histogram'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; import { createOptions } from '../../utils/build_query/create_options'; -import { QuerySourceResolver } from '../sources/resolvers'; import { SourceResolvers } from '../types'; export interface MatrixHistogramResolversDeps { matrixHistogram: MatrixHistogram; } -type QueryMatrixHistogramResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - export const createMatrixHistogramResolvers = ( libs: MatrixHistogramResolversDeps ): { Source: { - MatrixHistogram: QueryMatrixHistogramResolver; + MatrixHistogram: SourceResolvers['MatrixHistogram']; }; } => ({ Source: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/matrix_histogram/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/matrix_histogram/schema.gql.ts index deda6dc6e5c1a..7dd0cbe5ba13f 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/matrix_histogram/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/matrix_histogram/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const matrixHistogramSchema = gql` type MatrixOverTimeHistogramData { diff --git a/x-pack/legacy/plugins/siem/server/graphql/network/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/network/resolvers.ts index db15babc42a72..b99d026b33963 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/network/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/network/resolvers.ts @@ -5,30 +5,8 @@ */ import { SourceResolvers } from '../../graphql/types'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; import { Network } from '../../lib/network'; import { createOptionsPaginated } from '../../utils/build_query/create_options'; -import { QuerySourceResolver } from '../sources/resolvers'; - -type QueryNetworkTopCountriesResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - -type QueryNetworkTopNFlowResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - -type QueryNetworkHttpResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - -type QueryDnsResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; export interface NetworkResolversDeps { network: Network; @@ -38,10 +16,10 @@ export const createNetworkResolvers = ( libs: NetworkResolversDeps ): { Source: { - NetworkHttp: QueryNetworkHttpResolver; - NetworkTopCountries: QueryNetworkTopCountriesResolver; - NetworkTopNFlow: QueryNetworkTopNFlowResolver; - NetworkDns: QueryDnsResolver; + NetworkHttp: SourceResolvers['NetworkHttp']; + NetworkTopCountries: SourceResolvers['NetworkTopCountries']; + NetworkTopNFlow: SourceResolvers['NetworkTopNFlow']; + NetworkDns: SourceResolvers['NetworkDns']; }; } => ({ Source: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/network/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/network/schema.gql.ts index 15e2d832a73c9..c4d999cebb6f0 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/network/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/network/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const networkSchema = gql` enum NetworkDirectionEcs { diff --git a/x-pack/legacy/plugins/siem/server/graphql/note/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/note/resolvers.ts index 5f816b9ada54e..2f6c0f775d97d 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/note/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/note/resolvers.ts @@ -4,33 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AppResolverWithFields, AppResolverOf } from '../../lib/framework'; import { MutationResolvers, QueryResolvers } from '../types'; import { Note } from '../../lib/note/saved_object'; -export type QueryNoteResolver = AppResolverOf; - -export type QueryAllNoteResolver = AppResolverWithFields< - QueryResolvers.GetAllNotesResolver, - 'totalCount' | 'Note' ->; - -export type QueryNotesByTimelineIdResolver = AppResolverOf< - QueryResolvers.GetNotesByTimelineIdResolver ->; - -export type QueryNotesByEventIdResolver = AppResolverOf; - -export type MutationNoteResolver = AppResolverOf< - MutationResolvers.PersistNoteResolver ->; - -export type MutationDeleteNoteResolver = AppResolverOf; - -export type MutationDeleteNoteByTimelineIdResolver = AppResolverOf< - MutationResolvers.DeleteNoteByTimelineIdResolver ->; - interface NoteResolversDeps { note: Note; } @@ -39,15 +15,15 @@ export const createNoteResolvers = ( libs: NoteResolversDeps ): { Query: { - getNote: QueryNoteResolver; - getAllNotes: QueryAllNoteResolver; - getNotesByEventId: QueryNotesByEventIdResolver; - getNotesByTimelineId: QueryNotesByTimelineIdResolver; + getNote: QueryResolvers['getNote']; + getAllNotes: QueryResolvers['getAllNotes']; + getNotesByEventId: QueryResolvers['getNotesByEventId']; + getNotesByTimelineId: QueryResolvers['getNotesByTimelineId']; }; Mutation: { - deleteNote: MutationDeleteNoteResolver; - deleteNoteByTimelineId: MutationDeleteNoteByTimelineIdResolver; - persistNote: MutationNoteResolver; + deleteNote: MutationResolvers['deleteNote']; + deleteNoteByTimelineId: MutationResolvers['deleteNoteByTimelineId']; + persistNote: MutationResolvers['persistNote']; }; } => ({ Query: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/note/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/note/schema.gql.ts index fa26660d088c1..610d303d42b33 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/note/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/note/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; const note = ` eventId: String diff --git a/x-pack/legacy/plugins/siem/server/graphql/overview/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/overview/resolvers.ts index a7bafabb64092..beb9c8fc1a0e1 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/overview/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/overview/resolvers.ts @@ -5,20 +5,8 @@ */ import { SourceResolvers } from '../../graphql/types'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; import { Overview } from '../../lib/overview'; import { createOptions } from '../../utils/build_query/create_options'; -import { QuerySourceResolver } from '../sources/resolvers'; - -export type QueryOverviewNetworkResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - -export type QueryOverviewHostResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; export interface OverviewResolversDeps { overview: Overview; @@ -28,8 +16,8 @@ export const createOverviewResolvers = ( libs: OverviewResolversDeps ): { Source: { - OverviewHost: QueryOverviewHostResolver; - OverviewNetwork: QueryOverviewNetworkResolver; + OverviewHost: SourceResolvers['OverviewHost']; + OverviewNetwork: SourceResolvers['OverviewNetwork']; }; } => ({ Source: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/overview/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/overview/schema.gql.ts index 7ab4f9fdb18d6..ffb44dad1e3cf 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/overview/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/overview/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const overviewSchema = gql` type OverviewNetworkData { diff --git a/x-pack/legacy/plugins/siem/server/graphql/pinned_event/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/pinned_event/resolvers.ts index 49072f0279de8..77322120e265b 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/pinned_event/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/pinned_event/resolvers.ts @@ -4,26 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AppResolverOf } from '../../lib/framework'; import { MutationResolvers, QueryResolvers } from '../types'; import { PinnedEvent } from '../../lib/pinned_event/saved_object'; -export type QueryAllPinnedEventsByTimelineIdResolver = AppResolverOf< - QueryResolvers.GetAllPinnedEventsByTimelineIdResolver ->; - -export type MutationPinnedEventResolver = AppResolverOf< - MutationResolvers.PersistPinnedEventOnTimelineResolver ->; - -export type MutationDeletePinnedEventOnTimelineResolver = AppResolverOf< - MutationResolvers.DeletePinnedEventOnTimelineResolver ->; - -export type MutationDeleteAllPinnedEventsOnTimelineResolver = AppResolverOf< - MutationResolvers.DeleteAllPinnedEventsOnTimelineResolver ->; - interface TimelineResolversDeps { pinnedEvent: PinnedEvent; } @@ -32,12 +15,12 @@ export const createPinnedEventResolvers = ( libs: TimelineResolversDeps ): { Query: { - getAllPinnedEventsByTimelineId: QueryAllPinnedEventsByTimelineIdResolver; + getAllPinnedEventsByTimelineId: QueryResolvers['getAllPinnedEventsByTimelineId']; }; Mutation: { - persistPinnedEventOnTimeline: MutationPinnedEventResolver; - deletePinnedEventOnTimeline: MutationDeletePinnedEventOnTimelineResolver; - deleteAllPinnedEventsOnTimeline: MutationDeleteAllPinnedEventsOnTimelineResolver; + persistPinnedEventOnTimeline: MutationResolvers['persistPinnedEventOnTimeline']; + deletePinnedEventOnTimeline: MutationResolvers['deletePinnedEventOnTimeline']; + deleteAllPinnedEventsOnTimeline: MutationResolvers['deleteAllPinnedEventsOnTimeline']; }; } => ({ Query: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/pinned_event/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/pinned_event/schema.gql.ts index a797cd6720af2..1c139f12af8c1 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/pinned_event/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/pinned_event/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const pinnedEventSchema = gql` ######################### diff --git a/x-pack/legacy/plugins/siem/server/graphql/scalar_date/resolvers.test.ts b/x-pack/legacy/plugins/siem/server/graphql/scalar_date/resolvers.test.ts index 4779d77ed446e..a974c814cf0e4 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/scalar_date/resolvers.test.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/scalar_date/resolvers.test.ts @@ -38,7 +38,7 @@ describe('Test ScalarDate Resolver', () => { kind: 'IntValue', value: '1514782800000', }; - const date = dateScalar.parseLiteral(valueNode); + const date = dateScalar.parseLiteral(valueNode, {}); expect(date).toEqual(1514782800000); }); @@ -47,7 +47,7 @@ describe('Test ScalarDate Resolver', () => { kind: 'StringValue', value: '2018-01-01T05:00:00.000Z', }; - const date = dateScalar.parseLiteral(valueNode); + const date = dateScalar.parseLiteral(valueNode, {}); expect(date).toEqual('2018-01-01T05:00:00.000Z'); }); }); diff --git a/x-pack/legacy/plugins/siem/server/graphql/scalar_date/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/scalar_date/schema.gql.ts index c18f6ba98014b..e9b6864427930 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/scalar_date/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/scalar_date/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const dateSchema = gql` scalar Date diff --git a/x-pack/legacy/plugins/siem/server/graphql/scalar_to_any/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/scalar_to_any/schema.gql.ts index f0adde0945b5f..ead1865ec2d7b 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/scalar_to_any/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/scalar_to_any/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const toAnySchema = gql` scalar ToAny diff --git a/x-pack/legacy/plugins/siem/server/graphql/scalar_to_boolean_array/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/scalar_to_boolean_array/schema.gql.ts index a741adf3cd89f..48c7e2a02b967 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/scalar_to_boolean_array/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/scalar_to_boolean_array/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const toBooleanSchema = gql` scalar ToBooleanArray diff --git a/x-pack/legacy/plugins/siem/server/graphql/scalar_to_date_array/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/scalar_to_date_array/schema.gql.ts index e7ec88c0c12cb..afe16dc1f4987 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/scalar_to_date_array/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/scalar_to_date_array/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const toDateSchema = gql` scalar ToDateArray diff --git a/x-pack/legacy/plugins/siem/server/graphql/scalar_to_number_array/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/scalar_to_number_array/schema.gql.ts index 1fe85cacd0ea0..cecbb8b3a008b 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/scalar_to_number_array/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/scalar_to_number_array/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const toNumberSchema = gql` scalar ToNumberArray diff --git a/x-pack/legacy/plugins/siem/server/graphql/source_status/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/source_status/resolvers.ts index 24589822f0250..db18f4e7bcaa2 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/source_status/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/source_status/resolvers.ts @@ -5,28 +5,16 @@ */ import { SourceStatusResolvers } from '../../graphql/types'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; import { IndexFields } from '../../lib/index_fields'; import { SourceStatus } from '../../lib/source_status'; -import { QuerySourceResolver } from '../sources/resolvers'; - -export type SourceStatusIndicesExistResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; - -export type SourceStatusIndexFieldsResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; export const createSourceStatusResolvers = (libs: { sourceStatus: SourceStatus; fields: IndexFields; }): { SourceStatus: { - indicesExist: SourceStatusIndicesExistResolver; - indexFields: SourceStatusIndexFieldsResolver; + indicesExist: SourceStatusResolvers['indicesExist']; + indexFields: SourceStatusResolvers['indexFields']; }; } => ({ SourceStatus: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/source_status/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/source_status/schema.gql.ts index e484b60f8f364..bce13eb1f8f88 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/source_status/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/source_status/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const sourceStatusSchema = gql` "A descriptor of a field in an index" diff --git a/x-pack/legacy/plugins/siem/server/graphql/sources/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/sources/resolvers.ts index f3cccfa15b566..c59888bf37938 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/sources/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/sources/resolvers.ts @@ -4,45 +4,41 @@ * you may not use this file except in compliance with the Elastic License. */ -import { QueryResolvers, SourceResolvers } from '../../graphql/types'; import { - AppResolverOf, - AppResolverWithFields, - ChildResolverOf, - ResultOf, -} from '../../lib/framework'; + ResolversParentTypes, + Resolver, + ResolversTypes, + Maybe, + QuerySourceArgs, + RequireFields, +} from '../../graphql/types'; import { SourceStatus } from '../../lib/source_status'; import { Sources } from '../../lib/sources'; +import { SiemContext } from '../../lib/types'; -export type QuerySourceResolver = AppResolverWithFields< - QueryResolvers.SourceResolver, - 'id' | 'configuration' ->; - -export type QueryAllSourcesResolver = AppResolverWithFields< - QueryResolvers.AllSourcesResolver, - 'id' | 'configuration' ->; - -export type SourceStatusResolver = ChildResolverOf< - AppResolverOf>>, - QuerySourceResolver ->; - -export interface SourcesResolversDeps { +export const createSourcesResolvers = (libs: { sources: Sources; sourceStatus: SourceStatus; -} - -export const createSourcesResolvers = ( - libs: SourcesResolversDeps -): { +}): { Query: { - source: QuerySourceResolver; - allSources: QueryAllSourcesResolver; + source: Resolver< + Pick, + ResolversParentTypes['Source'], + SiemContext, + RequireFields + >; + allSources: Resolver< + Array>, + ResolversParentTypes['Source'], + SiemContext + >; }; Source: { - status: SourceStatusResolver; + status: Resolver< + Maybe, + ResolversParentTypes['SourceStatus'], + SiemContext + >; }; } => ({ Query: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/sources/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/sources/schema.gql.ts index f213b9db17c69..b60da4d2e95cb 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/sources/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/sources/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const sourcesSchema = gql` extend type Query { diff --git a/x-pack/legacy/plugins/siem/server/graphql/timeline/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/timeline/resolvers.ts index a33751179e93a..04edf0b7b62f9 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/timeline/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/timeline/resolvers.ts @@ -4,27 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AppResolverWithFields, AppResolverOf } from '../../lib/framework'; import { MutationResolvers, QueryResolvers } from '../types'; import { Timeline } from '../../lib/timeline/saved_object'; -export type QueryTimelineResolver = AppResolverOf; - -export type QueryAllTimelineResolver = AppResolverWithFields< - QueryResolvers.GetAllTimelineResolver, - 'totalCount' | 'timeline' ->; - -export type MutationTimelineResolver = AppResolverOf< - MutationResolvers.PersistTimelineResolver ->; - -export type MutationDeleteTimelineResolver = AppResolverOf< - MutationResolvers.DeleteTimelineResolver ->; - -export type MutationFavoriteResolver = AppResolverOf; - interface TimelineResolversDeps { timeline: Timeline; } @@ -33,13 +15,13 @@ export const createTimelineResolvers = ( libs: TimelineResolversDeps ): { Query: { - getOneTimeline: QueryTimelineResolver; - getAllTimeline: QueryAllTimelineResolver; + getOneTimeline: QueryResolvers['getOneTimeline']; + getAllTimeline: QueryResolvers['getAllTimeline']; }; Mutation: { - deleteTimeline: MutationDeleteTimelineResolver; - persistTimeline: MutationTimelineResolver; - persistFavorite: MutationFavoriteResolver; + deleteTimeline: MutationResolvers['deleteTimeline']; + persistTimeline: MutationResolvers['persistTimeline']; + persistFavorite: MutationResolvers['persistFavorite']; }; } => ({ Query: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/timeline/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/timeline/schema.gql.ts index 8b24cea0d6af9..aae73489e8170 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/timeline/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/timeline/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; const columnHeader = ` aggregatable: Boolean diff --git a/x-pack/legacy/plugins/siem/server/graphql/tls/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/tls/resolvers.ts index bfa3fddc3c8a5..72cf76c0603b7 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/tls/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/tls/resolvers.ts @@ -5,15 +5,8 @@ */ import { SourceResolvers } from '../../graphql/types'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; import { TLS, TlsRequestOptions } from '../../lib/tls'; import { createOptionsPaginated } from '../../utils/build_query/create_options'; -import { QuerySourceResolver } from '../sources/resolvers'; - -export type QueryTlsResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; export interface TlsResolversDeps { tls: TLS; @@ -23,7 +16,7 @@ export const createTlsResolvers = ( libs: TlsResolversDeps ): { Source: { - Tls: QueryTlsResolver; + Tls: SourceResolvers['Tls']; }; } => ({ Source: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/tls/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/tls/schema.gql.ts index 301960cea33ef..fda139109f275 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/tls/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/tls/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const tlsSchema = gql` enum TlsFields { diff --git a/x-pack/legacy/plugins/siem/server/graphql/types.ts b/x-pack/legacy/plugins/siem/server/graphql/types.ts index f42da48f2c1da..19b57c3519201 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/types.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/types.ts @@ -1,9189 +1,3876 @@ -/* tslint:disable */ -/* eslint-disable */ /* * 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. - */ +*/ + +/* tslint:disable */ +/* eslint-disable */ import { SiemContext } from '../lib/types'; +import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'; export type Maybe = T | null; - -export interface PageInfoNote { - pageIndex: number; - - pageSize: number; -} - -export interface SortNote { - sortField: SortFieldNote; - - sortOrder: Direction; -} - -export interface TimerangeInput { - /** The interval string to use for last bucket. The format is '{value}{unit}'. For example '5m' would return the metrics for the last 5 minutes of the timespan. */ - interval: string; - /** The end of the timerange */ - to: number; - /** The beginning of the timerange */ - from: number; -} - -export interface PaginationInputPaginated { - /** The activePage parameter defines the page of results you want to fetch */ - activePage: number; - /** The cursorStart parameter defines the start of the results to be displayed */ - cursorStart: number; - /** The fakePossibleCount parameter determines the total count in order to show 5 additional pages */ - fakePossibleCount: number; - /** The querySize parameter is the number of items to be returned */ - querySize: number; -} - -export interface PaginationInput { - /** The limit parameter allows you to configure the maximum amount of items to be returned */ - limit: number; - /** The cursor parameter defines the next result you want to fetch */ - cursor?: Maybe; - /** The tiebreaker parameter allow to be more precise to fetch the next item */ - tiebreaker?: Maybe; -} - -export interface SortField { - sortFieldId: string; - - direction: Direction; -} - -export interface LastTimeDetails { - hostName?: Maybe; - - ip?: Maybe; -} - -export interface HostsSortField { - field: HostsFields; - - direction: Direction; -} - -export interface UsersSortField { - field: UsersFields; - - direction: Direction; -} - -export interface NetworkTopTablesSortField { - field: NetworkTopTablesFields; - - direction: Direction; -} - -export interface NetworkDnsSortField { - field: NetworkDnsFields; - - direction: Direction; -} - -export interface NetworkHttpSortField { - direction: Direction; -} - -export interface TlsSortField { - field: TlsFields; - - direction: Direction; -} - -export interface PageInfoTimeline { - pageIndex: number; - - pageSize: number; -} - -export interface SortTimeline { - sortField: SortFieldTimeline; - - sortOrder: Direction; -} - -export interface NoteInput { - eventId?: Maybe; - - note?: Maybe; - - timelineId?: Maybe; -} - -export interface TimelineInput { - columns?: Maybe; - - dataProviders?: Maybe; - - description?: Maybe; - - eventType?: Maybe; - - filters?: Maybe; - - kqlMode?: Maybe; - - kqlQuery?: Maybe; - - title?: Maybe; - - dateRange?: Maybe; - - savedQueryId?: Maybe; - - sort?: Maybe; -} - -export interface ColumnHeaderInput { - aggregatable?: Maybe; - - category?: Maybe; - - columnHeaderType?: Maybe; - - description?: Maybe; - - example?: Maybe; - - indexes?: Maybe; - - id?: Maybe; - - name?: Maybe; - - placeholder?: Maybe; - - searchable?: Maybe; - - type?: Maybe; -} - -export interface DataProviderInput { - id?: Maybe; - - name?: Maybe; - - enabled?: Maybe; - - excluded?: Maybe; - - kqlQuery?: Maybe; - - queryMatch?: Maybe; - - and?: Maybe; -} - -export interface QueryMatchInput { - field?: Maybe; - - displayField?: Maybe; - - value?: Maybe; - - displayValue?: Maybe; - - operator?: Maybe; -} - -export interface FilterTimelineInput { - exists?: Maybe; - - meta?: Maybe; - - match_all?: Maybe; - - missing?: Maybe; - - query?: Maybe; - - range?: Maybe; - - script?: Maybe; -} - -export interface FilterMetaTimelineInput { - alias?: Maybe; - - controlledBy?: Maybe; - - disabled?: Maybe; - - field?: Maybe; - - formattedValue?: Maybe; - - index?: Maybe; - - key?: Maybe; - - negate?: Maybe; - - params?: Maybe; - - type?: Maybe; - - value?: Maybe; -} - -export interface SerializedFilterQueryInput { - filterQuery?: Maybe; -} - -export interface SerializedKueryQueryInput { - kuery?: Maybe; - - serializedQuery?: Maybe; -} - -export interface KueryFilterQueryInput { - kind?: Maybe; - - expression?: Maybe; -} - -export interface DateRangePickerInput { - start?: Maybe; - - end?: Maybe; -} - -export interface SortTimelineInput { - columnId?: Maybe; - - sortDirection?: Maybe; -} - -export interface FavoriteTimelineInput { - fullName?: Maybe; - - userName?: Maybe; - - favoriteDate?: Maybe; -} - -export enum SortFieldNote { - updatedBy = 'updatedBy', - updated = 'updated', -} - -export enum Direction { - asc = 'asc', - desc = 'desc', -} - -export enum LastEventIndexKey { - hostDetails = 'hostDetails', - hosts = 'hosts', - ipDetails = 'ipDetails', - network = 'network', -} - -export enum HostsFields { - hostName = 'hostName', - lastSeen = 'lastSeen', -} - -export enum UsersFields { - name = 'name', - count = 'count', -} - -export enum FlowTarget { - client = 'client', - destination = 'destination', - server = 'server', - source = 'source', +export type RequireFields = { [X in Exclude]?: T[X] } & { [P in K]-?: NonNullable }; + +/** All built-in and custom scalars, mapped to their actual values */ +export interface Scalars { + ID: string, + String: string, + Boolean: boolean, + Int: number, + Float: number, + ToStringArray: string[] | string, + Date: string, + ToNumberArray: number[] | number, + ToDateArray: string[] | string, + ToBooleanArray: boolean[] | boolean, + ToAny: any, + EsValue: any, } -export enum HistogramType { - authentications = 'authentications', - anomalies = 'anomalies', - events = 'events', - alerts = 'alerts', - dns = 'dns', +export interface AuditdData { + acct?: Maybe, + terminal?: Maybe, + op?: Maybe, } -export enum FlowTargetSourceDest { - destination = 'destination', - source = 'source', +export interface AuditdEcsFields { + result?: Maybe, + session?: Maybe, + data?: Maybe, + summary?: Maybe, + sequence?: Maybe, } -export enum NetworkTopTablesFields { - bytes_in = 'bytes_in', - bytes_out = 'bytes_out', - flows = 'flows', - destination_ips = 'destination_ips', - source_ips = 'source_ips', +export interface AuditEcsFields { + package?: Maybe, } -export enum NetworkDnsFields { - dnsName = 'dnsName', - queryCount = 'queryCount', - uniqueDomains = 'uniqueDomains', - dnsBytesIn = 'dnsBytesIn', - dnsBytesOut = 'dnsBytesOut', +export interface AuthEcsFields { + ssh?: Maybe, } -export enum TlsFields { - _id = '_id', +export interface AuthenticationItem { + _id: Scalars['String'], + failures: Scalars['Float'], + successes: Scalars['Float'], + user: UserEcsFields, + lastSuccess?: Maybe, + lastFailure?: Maybe, } -export enum SortFieldTimeline { - title = 'title', - description = 'description', - updated = 'updated', - created = 'created', +export interface AuthenticationsData { + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, } -export enum NetworkDirectionEcs { - inbound = 'inbound', - outbound = 'outbound', - internal = 'internal', - external = 'external', - incoming = 'incoming', - outgoing = 'outgoing', - listening = 'listening', - unknown = 'unknown', +export interface AuthenticationsEdges { + node: AuthenticationItem, + cursor: CursorType, } -export enum NetworkHttpFields { - domains = 'domains', - lastHost = 'lastHost', - lastSourceIp = 'lastSourceIp', - methods = 'methods', - path = 'path', - requestCount = 'requestCount', - statuses = 'statuses', +export interface AutonomousSystem { + number?: Maybe, + organization?: Maybe, } -export enum FlowDirection { - uniDirectional = 'uniDirectional', - biDirectional = 'biDirectional', +export interface AutonomousSystemItem { + name?: Maybe, + number?: Maybe, } -export type ToStringArray = string[] | string; - -export type Date = string; - -export type ToNumberArray = number[] | number; - -export type ToDateArray = string[] | string; - -export type ToBooleanArray = boolean[] | boolean; - -export type ToAny = any; - -export type EsValue = any; - -// ==================================================== -// Scalars -// ==================================================== - -// ==================================================== -// Types -// ==================================================== - -export interface Query { - getNote: NoteResult; - - getNotesByTimelineId: NoteResult[]; - - getNotesByEventId: NoteResult[]; - - getAllNotes: ResponseNotes; - - getAllPinnedEventsByTimelineId: PinnedEvent[]; - /** Get a security data source by id */ - source: Source; - /** Get a list of all security data sources */ - allSources: Source[]; - - getOneTimeline: TimelineResult; - - getAllTimeline: ResponseTimelines; -} - -export interface NoteResult { - eventId?: Maybe; - - note?: Maybe; - - timelineId?: Maybe; - - noteId: string; - - created?: Maybe; - - createdBy?: Maybe; - - timelineVersion?: Maybe; - - updated?: Maybe; - - updatedBy?: Maybe; - - version?: Maybe; -} - -export interface ResponseNotes { - notes: NoteResult[]; - - totalCount?: Maybe; -} - -export interface PinnedEvent { - code?: Maybe; - - message?: Maybe; - - pinnedEventId: string; - - eventId?: Maybe; - - timelineId?: Maybe; - - timelineVersion?: Maybe; - - created?: Maybe; - - createdBy?: Maybe; - - updated?: Maybe; - - updatedBy?: Maybe; - - version?: Maybe; -} - -export interface Source { - /** The id of the source */ - id: string; - /** The raw configuration of the source */ - configuration: SourceConfiguration; - /** The status of the source */ - status: SourceStatus; - /** Gets Authentication success and failures based on a timerange */ - Authentications: AuthenticationsData; - - Timeline: TimelineData; - - TimelineDetails: TimelineDetailsData; - - LastEventTime: LastEventTimeData; - /** Gets Hosts based on timerange and specified criteria, or all events in the timerange if no criteria is specified */ - Hosts: HostsData; - - HostOverview: HostItem; - - HostFirstLastSeen: FirstLastSeenHost; - - IpOverview?: Maybe; - - Users: UsersData; - - KpiNetwork?: Maybe; - - KpiHosts: KpiHostsData; - - KpiHostDetails: KpiHostDetailsData; - - MatrixHistogram: MatrixHistogramOverTimeData; - - NetworkTopCountries: NetworkTopCountriesData; - - NetworkTopNFlow: NetworkTopNFlowData; - - NetworkDns: NetworkDnsData; - - NetworkDnsHistogram: NetworkDsOverTimeData; - - NetworkHttp: NetworkHttpData; - - OverviewNetwork?: Maybe; - - OverviewHost?: Maybe; - - Tls: TlsData; - /** Gets UncommonProcesses based on a timerange, or all UncommonProcesses if no criteria is specified */ - UncommonProcesses: UncommonProcessesData; - /** Just a simple example to get the app name */ - whoAmI?: Maybe; -} - -/** A set of configuration options for a security data source */ -export interface SourceConfiguration { - /** The field mapping to use for this source */ - fields: SourceFields; -} - -/** A mapping of semantic fields to their document counterparts */ -export interface SourceFields { - /** The field to identify a container by */ - container: string; - /** The fields to identify a host by */ - host: string; - /** The fields that may contain the log event message. The first field found win. */ - message: string[]; - /** The field to identify a pod by */ - pod: string; - /** The field to use as a tiebreaker for log events that have identical timestamps */ - tiebreaker: string; - /** The field to use as a timestamp for metrics and logs */ - timestamp: string; -} - -/** The status of an infrastructure data source */ -export interface SourceStatus { - /** Whether the configured alias or wildcard pattern resolve to any auditbeat indices */ - indicesExist: boolean; - /** The list of fields defined in the index mappings */ - indexFields: IndexField[]; -} - -/** A descriptor of a field in an index */ -export interface IndexField { - /** Where the field belong */ - category: string; - /** Example of field's value */ - example?: Maybe; - /** whether the field's belong to an alias index */ - indexes: (Maybe)[]; - /** The name of the field */ - name: string; - /** The type of the field's values as recognized by Kibana */ - type: string; - /** Whether the field's values can be efficiently searched for */ - searchable: boolean; - /** Whether the field's values can be aggregated */ - aggregatable: boolean; - /** Description of the field */ - description?: Maybe; - - format?: Maybe; -} - -export interface AuthenticationsData { - edges: AuthenticationsEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface AuthenticationsEdges { - node: AuthenticationItem; - - cursor: CursorType; -} - -export interface AuthenticationItem { - _id: string; - - failures: number; - - successes: number; - - user: UserEcsFields; - - lastSuccess?: Maybe; - - lastFailure?: Maybe; -} - -export interface UserEcsFields { - domain?: Maybe; - - id?: Maybe; - - name?: Maybe; - - full_name?: Maybe; - - email?: Maybe; - - hash?: Maybe; - - group?: Maybe; -} - -export interface LastSourceHost { - timestamp?: Maybe; - - source?: Maybe; - - host?: Maybe; -} - -export interface SourceEcsFields { - bytes?: Maybe; - - ip?: Maybe; - - port?: Maybe; - - domain?: Maybe; - - geo?: Maybe; - - packets?: Maybe; -} - -export interface GeoEcsFields { - city_name?: Maybe; - - continent_name?: Maybe; - - country_iso_code?: Maybe; - - country_name?: Maybe; - - location?: Maybe; - - region_iso_code?: Maybe; - - region_name?: Maybe; -} - -export interface Location { - lon?: Maybe; - - lat?: Maybe; -} - -export interface HostEcsFields { - architecture?: Maybe; - - id?: Maybe; - - ip?: Maybe; - - mac?: Maybe; - - name?: Maybe; - - os?: Maybe; - - type?: Maybe; -} - -export interface OsEcsFields { - platform?: Maybe; - - name?: Maybe; - - full?: Maybe; - - family?: Maybe; - - version?: Maybe; - - kernel?: Maybe; -} - -export interface CursorType { - value?: Maybe; - - tiebreaker?: Maybe; -} - -export interface PageInfoPaginated { - activePage: number; - - fakeTotalCount: number; - - showMorePagesIndicator: boolean; -} - -export interface Inspect { - dsl: string[]; - - response: string[]; -} - -export interface TimelineData { - edges: TimelineEdges[]; - - totalCount: number; - - pageInfo: PageInfo; - - inspect?: Maybe; -} - -export interface TimelineEdges { - node: TimelineItem; - - cursor: CursorType; -} - -export interface TimelineItem { - _id: string; - - _index?: Maybe; - - data: TimelineNonEcsData[]; - - ecs: Ecs; -} - -export interface TimelineNonEcsData { - field: string; - - value?: Maybe; -} - -export interface Ecs { - _id: string; - - _index?: Maybe; - - auditd?: Maybe; - - destination?: Maybe; - - dns?: Maybe; - - endgame?: Maybe; - - event?: Maybe; - - geo?: Maybe; - - host?: Maybe; - - network?: Maybe; - - rule?: Maybe; - - signal?: Maybe; - - source?: Maybe; - - suricata?: Maybe; - - tls?: Maybe; - - zeek?: Maybe; - - http?: Maybe; - - url?: Maybe; - - timestamp?: Maybe; - - message?: Maybe; - - user?: Maybe; - - winlog?: Maybe; - - process?: Maybe; - - file?: Maybe; - - system?: Maybe; -} - -export interface AuditdEcsFields { - result?: Maybe; - - session?: Maybe; - - data?: Maybe; - - summary?: Maybe; - - sequence?: Maybe; -} - -export interface AuditdData { - acct?: Maybe; - - terminal?: Maybe; - - op?: Maybe; -} - -export interface Summary { - actor?: Maybe; - - object?: Maybe; - - how?: Maybe; - - message_type?: Maybe; - - sequence?: Maybe; -} - -export interface PrimarySecondary { - primary?: Maybe; - - secondary?: Maybe; - - type?: Maybe; -} - -export interface DestinationEcsFields { - bytes?: Maybe; - - ip?: Maybe; - - port?: Maybe; - - domain?: Maybe; - - geo?: Maybe; - - packets?: Maybe; -} - -export interface DnsEcsFields { - question?: Maybe; - - resolved_ip?: Maybe; - - response_code?: Maybe; -} - -export interface DnsQuestionData { - name?: Maybe; - - type?: Maybe; -} - -export interface EndgameEcsFields { - exit_code?: Maybe; - - file_name?: Maybe; - - file_path?: Maybe; - - logon_type?: Maybe; - - parent_process_name?: Maybe; - - pid?: Maybe; - - process_name?: Maybe; - - subject_domain_name?: Maybe; - - subject_logon_id?: Maybe; - - subject_user_name?: Maybe; - - target_domain_name?: Maybe; - - target_logon_id?: Maybe; - - target_user_name?: Maybe; -} - -export interface EventEcsFields { - action?: Maybe; - - category?: Maybe; - - code?: Maybe; - - created?: Maybe; - - dataset?: Maybe; - - duration?: Maybe; - - end?: Maybe; - - hash?: Maybe; - - id?: Maybe; - - kind?: Maybe; - - module?: Maybe; - - original?: Maybe; - - outcome?: Maybe; - - risk_score?: Maybe; - - risk_score_norm?: Maybe; - - severity?: Maybe; - - start?: Maybe; - - timezone?: Maybe; - - type?: Maybe; -} - -export interface NetworkEcsField { - bytes?: Maybe; - - community_id?: Maybe; - - direction?: Maybe; - - packets?: Maybe; - - protocol?: Maybe; - - transport?: Maybe; -} - -export interface RuleEcsField { - reference?: Maybe; -} - -export interface SignalField { - rule?: Maybe; - - original_time?: Maybe; -} - -export interface RuleField { - id?: Maybe; - - rule_id?: Maybe; - - false_positives: string[]; - - saved_id?: Maybe; - - timeline_id?: Maybe; - - timeline_title?: Maybe; - - max_signals?: Maybe; - - risk_score?: Maybe; - - output_index?: Maybe; - - description?: Maybe; - - from?: Maybe; - - immutable?: Maybe; - - index?: Maybe; - - interval?: Maybe; - - language?: Maybe; - - query?: Maybe; - - references?: Maybe; - - severity?: Maybe; - - tags?: Maybe; - - threat?: Maybe; - - type?: Maybe; - - size?: Maybe; - - to?: Maybe; - - enabled?: Maybe; - - filters?: Maybe; - - created_at?: Maybe; - - updated_at?: Maybe; - - created_by?: Maybe; - - updated_by?: Maybe; - - version?: Maybe; -} - -export interface SuricataEcsFields { - eve?: Maybe; -} - -export interface SuricataEveData { - alert?: Maybe; - - flow_id?: Maybe; - - proto?: Maybe; -} - -export interface SuricataAlertData { - signature?: Maybe; - - signature_id?: Maybe; -} - -export interface TlsEcsFields { - client_certificate?: Maybe; - - fingerprints?: Maybe; - - server_certificate?: Maybe; -} - -export interface TlsClientCertificateData { - fingerprint?: Maybe; -} - -export interface FingerprintData { - sha1?: Maybe; -} - -export interface TlsFingerprintsData { - ja3?: Maybe; -} - -export interface TlsJa3Data { - hash?: Maybe; -} - -export interface TlsServerCertificateData { - fingerprint?: Maybe; -} - -export interface ZeekEcsFields { - session_id?: Maybe; - - connection?: Maybe; - - notice?: Maybe; - - dns?: Maybe; - - http?: Maybe; - - files?: Maybe; - - ssl?: Maybe; -} - -export interface ZeekConnectionData { - local_resp?: Maybe; - - local_orig?: Maybe; - - missed_bytes?: Maybe; - - state?: Maybe; - - history?: Maybe; -} - -export interface ZeekNoticeData { - suppress_for?: Maybe; - - msg?: Maybe; - - note?: Maybe; - - sub?: Maybe; - - dst?: Maybe; - - dropped?: Maybe; - - peer_descr?: Maybe; -} - -export interface ZeekDnsData { - AA?: Maybe; - - qclass_name?: Maybe; - - RD?: Maybe; - - qtype_name?: Maybe; - - rejected?: Maybe; - - qtype?: Maybe; - - query?: Maybe; - - trans_id?: Maybe; - - qclass?: Maybe; - - RA?: Maybe; - - TC?: Maybe; -} - -export interface ZeekHttpData { - resp_mime_types?: Maybe; - - trans_depth?: Maybe; - - status_msg?: Maybe; - - resp_fuids?: Maybe; - - tags?: Maybe; -} - -export interface ZeekFileData { - session_ids?: Maybe; - - timedout?: Maybe; - - local_orig?: Maybe; - - tx_host?: Maybe; - - source?: Maybe; - - is_orig?: Maybe; - - overflow_bytes?: Maybe; - - sha1?: Maybe; - - duration?: Maybe; - - depth?: Maybe; - - analyzers?: Maybe; - - mime_type?: Maybe; - - rx_host?: Maybe; - - total_bytes?: Maybe; - - fuid?: Maybe; - - seen_bytes?: Maybe; - - missing_bytes?: Maybe; - - md5?: Maybe; -} - -export interface ZeekSslData { - cipher?: Maybe; - - established?: Maybe; - - resumed?: Maybe; - - version?: Maybe; -} - -export interface HttpEcsFields { - version?: Maybe; - - request?: Maybe; - - response?: Maybe; -} - -export interface HttpRequestData { - method?: Maybe; - - body?: Maybe; - - referrer?: Maybe; - - bytes?: Maybe; -} - -export interface HttpBodyData { - content?: Maybe; - - bytes?: Maybe; -} - -export interface HttpResponseData { - status_code?: Maybe; - - body?: Maybe; - - bytes?: Maybe; -} - -export interface UrlEcsFields { - domain?: Maybe; - - original?: Maybe; - - username?: Maybe; - - password?: Maybe; -} - -export interface WinlogEcsFields { - event_id?: Maybe; -} - -export interface ProcessEcsFields { - hash?: Maybe; - - pid?: Maybe; - - name?: Maybe; - - ppid?: Maybe; - - args?: Maybe; - - executable?: Maybe; - - title?: Maybe; - - thread?: Maybe; - - working_directory?: Maybe; -} - -export interface ProcessHashData { - md5?: Maybe; - - sha1?: Maybe; - - sha256?: Maybe; -} - -export interface Thread { - id?: Maybe; - - start?: Maybe; -} - -export interface FileFields { - name?: Maybe; - - path?: Maybe; - - target_path?: Maybe; - - extension?: Maybe; - - type?: Maybe; - - device?: Maybe; - - inode?: Maybe; - - uid?: Maybe; - - owner?: Maybe; - - gid?: Maybe; - - group?: Maybe; - - mode?: Maybe; - - size?: Maybe; - - mtime?: Maybe; - - ctime?: Maybe; -} - -export interface SystemEcsField { - audit?: Maybe; - - auth?: Maybe; -} - -export interface AuditEcsFields { - package?: Maybe; -} - -export interface PackageEcsFields { - arch?: Maybe; - - entity_id?: Maybe; - - name?: Maybe; - - size?: Maybe; - - summary?: Maybe; - - version?: Maybe; -} - -export interface AuthEcsFields { - ssh?: Maybe; -} - -export interface SshEcsFields { - method?: Maybe; - - signature?: Maybe; -} - -export interface PageInfo { - endCursor?: Maybe; - - hasNextPage?: Maybe; -} - -export interface TimelineDetailsData { - data?: Maybe; - - inspect?: Maybe; -} - -export interface DetailItem { - field: string; - - values?: Maybe; - - originalValue?: Maybe; -} - -export interface LastEventTimeData { - lastSeen?: Maybe; - - inspect?: Maybe; -} - -export interface HostsData { - edges: HostsEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface HostsEdges { - node: HostItem; - - cursor: CursorType; -} - -export interface HostItem { - _id?: Maybe; - - lastSeen?: Maybe; - - host?: Maybe; - - cloud?: Maybe; - - inspect?: Maybe; -} - -export interface CloudFields { - instance?: Maybe; - - machine?: Maybe; - - provider?: Maybe<(Maybe)[]>; - - region?: Maybe<(Maybe)[]>; -} - -export interface CloudInstance { - id?: Maybe<(Maybe)[]>; -} - -export interface CloudMachine { - type?: Maybe<(Maybe)[]>; -} - -export interface FirstLastSeenHost { - inspect?: Maybe; - - firstSeen?: Maybe; - - lastSeen?: Maybe; -} - -export interface IpOverviewData { - client?: Maybe; - - destination?: Maybe; - - host: HostEcsFields; - - server?: Maybe; - - source?: Maybe; - - inspect?: Maybe; -} - -export interface Overview { - firstSeen?: Maybe; - - lastSeen?: Maybe; - - autonomousSystem: AutonomousSystem; - - geo: GeoEcsFields; -} - -export interface AutonomousSystem { - number?: Maybe; - - organization?: Maybe; -} - -export interface AutonomousSystemOrganization { - name?: Maybe; -} - -export interface UsersData { - edges: UsersEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface UsersEdges { - node: UsersNode; - - cursor: CursorType; -} - -export interface UsersNode { - _id?: Maybe; - - timestamp?: Maybe; - - user?: Maybe; -} - -export interface UsersItem { - name?: Maybe; - - id?: Maybe; - - groupId?: Maybe; - - groupName?: Maybe; - - count?: Maybe; -} - -export interface KpiNetworkData { - networkEvents?: Maybe; - - uniqueFlowId?: Maybe; - - uniqueSourcePrivateIps?: Maybe; - - uniqueSourcePrivateIpsHistogram?: Maybe; - - uniqueDestinationPrivateIps?: Maybe; - - uniqueDestinationPrivateIpsHistogram?: Maybe; - - dnsQueries?: Maybe; - - tlsHandshakes?: Maybe; - - inspect?: Maybe; -} - -export interface KpiNetworkHistogramData { - x?: Maybe; - - y?: Maybe; -} - -export interface KpiHostsData { - hosts?: Maybe; - - hostsHistogram?: Maybe; - - authSuccess?: Maybe; - - authSuccessHistogram?: Maybe; - - authFailure?: Maybe; - - authFailureHistogram?: Maybe; - - uniqueSourceIps?: Maybe; - - uniqueSourceIpsHistogram?: Maybe; - - uniqueDestinationIps?: Maybe; - - uniqueDestinationIpsHistogram?: Maybe; - - inspect?: Maybe; -} - -export interface KpiHostHistogramData { - x?: Maybe; - - y?: Maybe; -} - -export interface KpiHostDetailsData { - authSuccess?: Maybe; - - authSuccessHistogram?: Maybe; - - authFailure?: Maybe; - - authFailureHistogram?: Maybe; - - uniqueSourceIps?: Maybe; - - uniqueSourceIpsHistogram?: Maybe; - - uniqueDestinationIps?: Maybe; - - uniqueDestinationIpsHistogram?: Maybe; - - inspect?: Maybe; -} - -export interface MatrixHistogramOverTimeData { - inspect?: Maybe; - - matrixHistogramData: MatrixOverTimeHistogramData[]; - - totalCount: number; -} - -export interface MatrixOverTimeHistogramData { - x?: Maybe; - - y?: Maybe; - - g?: Maybe; -} - -export interface NetworkTopCountriesData { - edges: NetworkTopCountriesEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface NetworkTopCountriesEdges { - node: NetworkTopCountriesItem; - - cursor: CursorType; -} - -export interface NetworkTopCountriesItem { - _id?: Maybe; - - source?: Maybe; - - destination?: Maybe; - - network?: Maybe; -} - -export interface TopCountriesItemSource { - country?: Maybe; - - destination_ips?: Maybe; - - flows?: Maybe; - - location?: Maybe; - - source_ips?: Maybe; -} - -export interface GeoItem { - geo?: Maybe; - - flowTarget?: Maybe; -} - -export interface TopCountriesItemDestination { - country?: Maybe; - - destination_ips?: Maybe; - - flows?: Maybe; - - location?: Maybe; - - source_ips?: Maybe; -} - -export interface TopNetworkTablesEcsField { - bytes_in?: Maybe; - - bytes_out?: Maybe; -} - -export interface NetworkTopNFlowData { - edges: NetworkTopNFlowEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface NetworkTopNFlowEdges { - node: NetworkTopNFlowItem; - - cursor: CursorType; -} - -export interface NetworkTopNFlowItem { - _id?: Maybe; - - source?: Maybe; - - destination?: Maybe; - - network?: Maybe; -} - -export interface TopNFlowItemSource { - autonomous_system?: Maybe; - - domain?: Maybe; - - ip?: Maybe; - - location?: Maybe; - - flows?: Maybe; - - destination_ips?: Maybe; -} - -export interface AutonomousSystemItem { - name?: Maybe; - - number?: Maybe; -} - -export interface TopNFlowItemDestination { - autonomous_system?: Maybe; - - domain?: Maybe; - - ip?: Maybe; - - location?: Maybe; - - flows?: Maybe; - - source_ips?: Maybe; -} - -export interface NetworkDnsData { - edges: NetworkDnsEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; - - histogram?: Maybe; -} - -export interface NetworkDnsEdges { - node: NetworkDnsItem; - - cursor: CursorType; -} - -export interface NetworkDnsItem { - _id?: Maybe; - - dnsBytesIn?: Maybe; - - dnsBytesOut?: Maybe; - - dnsName?: Maybe; - - queryCount?: Maybe; - - uniqueDomains?: Maybe; -} - -export interface MatrixOverOrdinalHistogramData { - x: string; - - y: number; - - g: string; -} - -export interface NetworkDsOverTimeData { - inspect?: Maybe; - - matrixHistogramData: MatrixOverTimeHistogramData[]; - - totalCount: number; -} - -export interface NetworkHttpData { - edges: NetworkHttpEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface NetworkHttpEdges { - node: NetworkHttpItem; - - cursor: CursorType; -} - -export interface NetworkHttpItem { - _id?: Maybe; - - domains: string[]; - - lastHost?: Maybe; - - lastSourceIp?: Maybe; - - methods: string[]; - - path?: Maybe; - - requestCount?: Maybe; - - statuses: string[]; -} - -export interface OverviewNetworkData { - auditbeatSocket?: Maybe; - - filebeatCisco?: Maybe; - - filebeatNetflow?: Maybe; - - filebeatPanw?: Maybe; - - filebeatSuricata?: Maybe; - - filebeatZeek?: Maybe; - - packetbeatDNS?: Maybe; - - packetbeatFlow?: Maybe; - - packetbeatTLS?: Maybe; - - inspect?: Maybe; -} - -export interface OverviewHostData { - auditbeatAuditd?: Maybe; - - auditbeatFIM?: Maybe; - - auditbeatLogin?: Maybe; - - auditbeatPackage?: Maybe; - - auditbeatProcess?: Maybe; - - auditbeatUser?: Maybe; - - endgameDns?: Maybe; - - endgameFile?: Maybe; - - endgameImageLoad?: Maybe; - - endgameNetwork?: Maybe; - - endgameProcess?: Maybe; - - endgameRegistry?: Maybe; - - endgameSecurity?: Maybe; - - filebeatSystemModule?: Maybe; - - winlogbeatSecurity?: Maybe; - - winlogbeatMWSysmonOperational?: Maybe; - - inspect?: Maybe; -} - -export interface TlsData { - edges: TlsEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface TlsEdges { - node: TlsNode; - - cursor: CursorType; -} - -export interface TlsNode { - _id?: Maybe; - - timestamp?: Maybe; - - alternativeNames?: Maybe; - - notAfter?: Maybe; - - commonNames?: Maybe; - - ja3?: Maybe; - - issuerNames?: Maybe; -} - -export interface UncommonProcessesData { - edges: UncommonProcessesEdges[]; - - totalCount: number; - - pageInfo: PageInfoPaginated; - - inspect?: Maybe; -} - -export interface UncommonProcessesEdges { - node: UncommonProcessItem; - - cursor: CursorType; -} - -export interface UncommonProcessItem { - _id: string; - - instances: number; - - process: ProcessEcsFields; - - hosts: HostEcsFields[]; - - user?: Maybe; -} - -export interface SayMyName { - /** The id of the source */ - appName: string; -} - -export interface TimelineResult { - columns?: Maybe; - - created?: Maybe; - - createdBy?: Maybe; - - dataProviders?: Maybe; - - dateRange?: Maybe; - - description?: Maybe; - - eventIdToNoteIds?: Maybe; - - eventType?: Maybe; - - favorite?: Maybe; - - filters?: Maybe; - - kqlMode?: Maybe; - - kqlQuery?: Maybe; - - notes?: Maybe; - - noteIds?: Maybe; - - pinnedEventIds?: Maybe; - - pinnedEventsSaveObject?: Maybe; - - savedQueryId?: Maybe; - - savedObjectId: string; - - sort?: Maybe; - - title?: Maybe; - - updated?: Maybe; - - updatedBy?: Maybe; - - version: string; -} - -export interface ColumnHeaderResult { - aggregatable?: Maybe; - - category?: Maybe; - - columnHeaderType?: Maybe; - - description?: Maybe; - - example?: Maybe; - - indexes?: Maybe; - - id?: Maybe; - - name?: Maybe; - - placeholder?: Maybe; - - searchable?: Maybe; - - type?: Maybe; -} - -export interface DataProviderResult { - id?: Maybe; - - name?: Maybe; - - enabled?: Maybe; - - excluded?: Maybe; - - kqlQuery?: Maybe; - - queryMatch?: Maybe; - - and?: Maybe; -} - -export interface QueryMatchResult { - field?: Maybe; - - displayField?: Maybe; - - value?: Maybe; - - displayValue?: Maybe; - - operator?: Maybe; -} - -export interface DateRangePickerResult { - start?: Maybe; - - end?: Maybe; -} - -export interface FavoriteTimelineResult { - fullName?: Maybe; - - userName?: Maybe; - - favoriteDate?: Maybe; -} - -export interface FilterTimelineResult { - exists?: Maybe; - - meta?: Maybe; - - match_all?: Maybe; - - missing?: Maybe; - - query?: Maybe; - - range?: Maybe; - - script?: Maybe; -} - -export interface FilterMetaTimelineResult { - alias?: Maybe; - - controlledBy?: Maybe; - - disabled?: Maybe; - - field?: Maybe; - - formattedValue?: Maybe; - - index?: Maybe; - - key?: Maybe; - - negate?: Maybe; - - params?: Maybe; - - type?: Maybe; +export interface AutonomousSystemOrganization { + name?: Maybe, +} - value?: Maybe; +export interface CloudFields { + instance?: Maybe, + machine?: Maybe, + provider?: Maybe>>, + region?: Maybe>>, } -export interface SerializedFilterQueryResult { - filterQuery?: Maybe; +export interface CloudInstance { + id?: Maybe>>, } -export interface SerializedKueryQueryResult { - kuery?: Maybe; +export interface CloudMachine { + type?: Maybe>>, +} - serializedQuery?: Maybe; +export interface ColumnHeaderInput { + aggregatable?: Maybe, + category?: Maybe, + columnHeaderType?: Maybe, + description?: Maybe, + example?: Maybe, + indexes?: Maybe>, + id?: Maybe, + name?: Maybe, + placeholder?: Maybe, + searchable?: Maybe, + type?: Maybe, } -export interface KueryFilterQueryResult { - kind?: Maybe; +export interface ColumnHeaderResult { + aggregatable?: Maybe, + category?: Maybe, + columnHeaderType?: Maybe, + description?: Maybe, + example?: Maybe, + indexes?: Maybe>, + id?: Maybe, + name?: Maybe, + placeholder?: Maybe, + searchable?: Maybe, + type?: Maybe, +} - expression?: Maybe; +export interface CursorType { + value?: Maybe, + tiebreaker?: Maybe, } -export interface SortTimelineResult { - columnId?: Maybe; +export interface DataProviderInput { + id?: Maybe, + name?: Maybe, + enabled?: Maybe, + excluded?: Maybe, + kqlQuery?: Maybe, + queryMatch?: Maybe, + and?: Maybe>, +} - sortDirection?: Maybe; +export interface DataProviderResult { + id?: Maybe, + name?: Maybe, + enabled?: Maybe, + excluded?: Maybe, + kqlQuery?: Maybe, + queryMatch?: Maybe, + and?: Maybe>, } -export interface ResponseTimelines { - timeline: (Maybe)[]; - totalCount?: Maybe; +export interface DateRangePickerInput { + start?: Maybe, + end?: Maybe, } -export interface Mutation { - /** Persists a note */ - persistNote: ResponseNote; +export interface DateRangePickerResult { + start?: Maybe, + end?: Maybe, +} - deleteNote?: Maybe; +export interface DestinationEcsFields { + bytes?: Maybe, + ip?: Maybe, + port?: Maybe, + domain?: Maybe, + geo?: Maybe, + packets?: Maybe, +} - deleteNoteByTimelineId?: Maybe; - /** Persists a pinned event in a timeline */ - persistPinnedEventOnTimeline?: Maybe; - /** Remove a pinned events in a timeline */ - deletePinnedEventOnTimeline: boolean; - /** Remove all pinned events in a timeline */ - deleteAllPinnedEventsOnTimeline: boolean; - /** Persists a timeline */ - persistTimeline: ResponseTimeline; +export interface DetailItem { + field: Scalars['String'], + values?: Maybe, + originalValue?: Maybe, +} - persistFavorite: ResponseFavoriteTimeline; +export enum Direction { + asc = 'asc', + desc = 'desc' +} - deleteTimeline: boolean; +export interface DnsEcsFields { + question?: Maybe, + resolved_ip?: Maybe, + response_code?: Maybe, } -export interface ResponseNote { - code?: Maybe; +export interface DnsQuestionData { + name?: Maybe, + type?: Maybe, +} - message?: Maybe; +export interface Ecs { + _id: Scalars['String'], + _index?: Maybe, + auditd?: Maybe, + destination?: Maybe, + dns?: Maybe, + endgame?: Maybe, + event?: Maybe, + geo?: Maybe, + host?: Maybe, + network?: Maybe, + rule?: Maybe, + signal?: Maybe, + source?: Maybe, + suricata?: Maybe, + tls?: Maybe, + zeek?: Maybe, + http?: Maybe, + url?: Maybe, + timestamp?: Maybe, + message?: Maybe, + user?: Maybe, + winlog?: Maybe, + process?: Maybe, + file?: Maybe, + system?: Maybe, +} - note: NoteResult; +export interface EcsEdges { + node: Ecs, + cursor: CursorType, } -export interface ResponseTimeline { - code?: Maybe; +export interface EndgameEcsFields { + exit_code?: Maybe, + file_name?: Maybe, + file_path?: Maybe, + logon_type?: Maybe, + parent_process_name?: Maybe, + pid?: Maybe, + process_name?: Maybe, + subject_domain_name?: Maybe, + subject_logon_id?: Maybe, + subject_user_name?: Maybe, + target_domain_name?: Maybe, + target_logon_id?: Maybe, + target_user_name?: Maybe, +} - message?: Maybe; - timeline: TimelineResult; +export interface EventEcsFields { + action?: Maybe, + category?: Maybe, + code?: Maybe, + created?: Maybe, + dataset?: Maybe, + duration?: Maybe, + end?: Maybe, + hash?: Maybe, + id?: Maybe, + kind?: Maybe, + module?: Maybe, + original?: Maybe, + outcome?: Maybe, + risk_score?: Maybe, + risk_score_norm?: Maybe, + severity?: Maybe, + start?: Maybe, + timezone?: Maybe, + type?: Maybe, } -export interface ResponseFavoriteTimeline { - code?: Maybe; +export interface EventsTimelineData { + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfo, + inspect?: Maybe, +} - message?: Maybe; +export interface FavoriteTimelineInput { + fullName?: Maybe, + userName?: Maybe, + favoriteDate?: Maybe, +} - savedObjectId: string; +export interface FavoriteTimelineResult { + fullName?: Maybe, + userName?: Maybe, + favoriteDate?: Maybe, +} - version: string; +export interface FileFields { + name?: Maybe, + path?: Maybe, + target_path?: Maybe, + extension?: Maybe, + type?: Maybe, + device?: Maybe, + inode?: Maybe, + uid?: Maybe, + owner?: Maybe, + gid?: Maybe, + group?: Maybe, + mode?: Maybe, + size?: Maybe, + mtime?: Maybe, + ctime?: Maybe, +} - favorite?: Maybe; +export interface FilterMetaTimelineInput { + alias?: Maybe, + controlledBy?: Maybe, + disabled?: Maybe, + field?: Maybe, + formattedValue?: Maybe, + index?: Maybe, + key?: Maybe, + negate?: Maybe, + params?: Maybe, + type?: Maybe, + value?: Maybe, } -export interface EcsEdges { - node: Ecs; +export interface FilterMetaTimelineResult { + alias?: Maybe, + controlledBy?: Maybe, + disabled?: Maybe, + field?: Maybe, + formattedValue?: Maybe, + index?: Maybe, + key?: Maybe, + negate?: Maybe, + params?: Maybe, + type?: Maybe, + value?: Maybe, +} - cursor: CursorType; +export interface FilterTimelineInput { + exists?: Maybe, + meta?: Maybe, + match_all?: Maybe, + missing?: Maybe, + query?: Maybe, + range?: Maybe, + script?: Maybe, } -export interface EventsTimelineData { - edges: EcsEdges[]; +export interface FilterTimelineResult { + exists?: Maybe, + meta?: Maybe, + match_all?: Maybe, + missing?: Maybe, + query?: Maybe, + range?: Maybe, + script?: Maybe, +} - totalCount: number; +export interface FingerprintData { + sha1?: Maybe, +} - pageInfo: PageInfo; +export interface FirstLastSeenHost { + inspect?: Maybe, + firstSeen?: Maybe, + lastSeen?: Maybe, +} - inspect?: Maybe; +export enum FlowDirection { + uniDirectional = 'uniDirectional', + biDirectional = 'biDirectional' } -export interface OsFields { - platform?: Maybe; +export enum FlowTarget { + client = 'client', + destination = 'destination', + server = 'server', + source = 'source' +} - name?: Maybe; +export enum FlowTargetSourceDest { + destination = 'destination', + source = 'source' +} - full?: Maybe; +export interface GeoEcsFields { + city_name?: Maybe, + continent_name?: Maybe, + country_iso_code?: Maybe, + country_name?: Maybe, + location?: Maybe, + region_iso_code?: Maybe, + region_name?: Maybe, +} - family?: Maybe; +export interface GeoItem { + geo?: Maybe, + flowTarget?: Maybe, +} - version?: Maybe; +export enum HistogramType { + authentications = 'authentications', + anomalies = 'anomalies', + events = 'events', + alerts = 'alerts', + dns = 'dns' +} - kernel?: Maybe; +export interface HostEcsFields { + architecture?: Maybe, + id?: Maybe, + ip?: Maybe, + mac?: Maybe, + name?: Maybe, + os?: Maybe, + type?: Maybe, } export interface HostFields { - architecture?: Maybe; - - id?: Maybe; + architecture?: Maybe, + id?: Maybe, + ip?: Maybe>>, + mac?: Maybe>>, + name?: Maybe, + os?: Maybe, + type?: Maybe, +} - ip?: Maybe<(Maybe)[]>; +export interface HostItem { + _id?: Maybe, + lastSeen?: Maybe, + host?: Maybe, + cloud?: Maybe, + inspect?: Maybe, +} - mac?: Maybe<(Maybe)[]>; +export interface HostsData { + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +} - name?: Maybe; +export interface HostsEdges { + node: HostItem, + cursor: CursorType, +} - os?: Maybe; +export enum HostsFields { + hostName = 'hostName', + lastSeen = 'lastSeen' +} - type?: Maybe; +export interface HostsSortField { + field: HostsFields, + direction: Direction, } -// ==================================================== -// Arguments -// ==================================================== +export interface HttpBodyData { + content?: Maybe, + bytes?: Maybe, +} -export interface GetNoteQueryArgs { - id: string; +export interface HttpEcsFields { + version?: Maybe, + request?: Maybe, + response?: Maybe, } -export interface GetNotesByTimelineIdQueryArgs { - timelineId: string; + +export interface HttpRequestData { + method?: Maybe, + body?: Maybe, + referrer?: Maybe, + bytes?: Maybe, } -export interface GetNotesByEventIdQueryArgs { - eventId: string; + +export interface HttpResponseData { + status_code?: Maybe, + body?: Maybe, + bytes?: Maybe, } -export interface GetAllNotesQueryArgs { - pageInfo?: Maybe; - search?: Maybe; +/** A descriptor of a field in an index */ +export interface IndexField { + /** Where the field belong */ + category: Scalars['String'], + /** Example of field's value */ + example?: Maybe, + /** whether the field's belong to an alias index */ + indexes: Array>, + /** The name of the field */ + name: Scalars['String'], + /** The type of the field's values as recognized by Kibana */ + type: Scalars['String'], + /** Whether the field's values can be efficiently searched for */ + searchable: Scalars['Boolean'], + /** Whether the field's values can be aggregated */ + aggregatable: Scalars['Boolean'], + /** Description of the field */ + description?: Maybe, + format?: Maybe, +} - sort?: Maybe; +export interface Inspect { + dsl: Array, + response: Array, } -export interface GetAllPinnedEventsByTimelineIdQueryArgs { - timelineId: string; + +export interface IpOverviewData { + client?: Maybe, + destination?: Maybe, + host: HostEcsFields, + server?: Maybe, + source?: Maybe, + inspect?: Maybe, } -export interface SourceQueryArgs { - /** The id of the source */ - id: string; + +export interface KpiHostDetailsData { + authSuccess?: Maybe, + authSuccessHistogram?: Maybe>, + authFailure?: Maybe, + authFailureHistogram?: Maybe>, + uniqueSourceIps?: Maybe, + uniqueSourceIpsHistogram?: Maybe>, + uniqueDestinationIps?: Maybe, + uniqueDestinationIpsHistogram?: Maybe>, + inspect?: Maybe, } -export interface GetOneTimelineQueryArgs { - id: string; + +export interface KpiHostHistogramData { + x?: Maybe, + y?: Maybe, } -export interface GetAllTimelineQueryArgs { - pageInfo?: Maybe; - search?: Maybe; +export interface KpiHostsData { + hosts?: Maybe, + hostsHistogram?: Maybe>, + authSuccess?: Maybe, + authSuccessHistogram?: Maybe>, + authFailure?: Maybe, + authFailureHistogram?: Maybe>, + uniqueSourceIps?: Maybe, + uniqueSourceIpsHistogram?: Maybe>, + uniqueDestinationIps?: Maybe, + uniqueDestinationIpsHistogram?: Maybe>, + inspect?: Maybe, +} - sort?: Maybe; +export interface KpiNetworkData { + networkEvents?: Maybe, + uniqueFlowId?: Maybe, + uniqueSourcePrivateIps?: Maybe, + uniqueSourcePrivateIpsHistogram?: Maybe>, + uniqueDestinationPrivateIps?: Maybe, + uniqueDestinationPrivateIpsHistogram?: Maybe>, + dnsQueries?: Maybe, + tlsHandshakes?: Maybe, + inspect?: Maybe, +} - onlyUserFavorite?: Maybe; +export interface KpiNetworkHistogramData { + x?: Maybe, + y?: Maybe, } -export interface AuthenticationsSourceArgs { - timerange: TimerangeInput; - pagination: PaginationInputPaginated; +export interface KueryFilterQueryInput { + kind?: Maybe, + expression?: Maybe, +} - filterQuery?: Maybe; +export interface KueryFilterQueryResult { + kind?: Maybe, + expression?: Maybe, +} - defaultIndex: string[]; +export enum LastEventIndexKey { + hostDetails = 'hostDetails', + hosts = 'hosts', + ipDetails = 'ipDetails', + network = 'network' } -export interface TimelineSourceArgs { - pagination: PaginationInput; - sortField: SortField; +export interface LastEventTimeData { + lastSeen?: Maybe, + inspect?: Maybe, +} - fieldRequested: string[]; +export interface LastSourceHost { + timestamp?: Maybe, + source?: Maybe, + host?: Maybe, +} - timerange?: Maybe; +export interface LastTimeDetails { + hostName?: Maybe, + ip?: Maybe, +} - filterQuery?: Maybe; +export interface Location { + lon?: Maybe, + lat?: Maybe, +} - defaultIndex: string[]; +export interface MatrixHistogramOverTimeData { + inspect?: Maybe, + matrixHistogramData: Array, + totalCount: Scalars['Float'], } -export interface TimelineDetailsSourceArgs { - eventId: string; - indexName: string; +export interface MatrixOverOrdinalHistogramData { + x: Scalars['String'], + y: Scalars['Float'], + g: Scalars['String'], +} - defaultIndex: string[]; +export interface MatrixOverTimeHistogramData { + x?: Maybe, + y?: Maybe, + g?: Maybe, } -export interface LastEventTimeSourceArgs { - id?: Maybe; - indexKey: LastEventIndexKey; +export interface Mutation { + /** Persists a note */ + persistNote: ResponseNote, + deleteNote?: Maybe, + deleteNoteByTimelineId?: Maybe, + /** Persists a pinned event in a timeline */ + persistPinnedEventOnTimeline?: Maybe, + /** Remove a pinned events in a timeline */ + deletePinnedEventOnTimeline: Scalars['Boolean'], + /** Remove all pinned events in a timeline */ + deleteAllPinnedEventsOnTimeline: Scalars['Boolean'], + /** Persists a timeline */ + persistTimeline: ResponseTimeline, + persistFavorite: ResponseFavoriteTimeline, + deleteTimeline: Scalars['Boolean'], +} - details: LastTimeDetails; - defaultIndex: string[]; +export interface MutationPersistNoteArgs { + noteId?: Maybe, + version?: Maybe, + note: NoteInput } -export interface HostsSourceArgs { - id?: Maybe; - timerange: TimerangeInput; - pagination: PaginationInputPaginated; - - sort: HostsSortField; +export interface MutationDeleteNoteArgs { + id: Array +} - filterQuery?: Maybe; - defaultIndex: string[]; +export interface MutationDeleteNoteByTimelineIdArgs { + timelineId: Scalars['ID'], + version?: Maybe } -export interface HostOverviewSourceArgs { - id?: Maybe; - hostName: string; - timerange: TimerangeInput; +export interface MutationPersistPinnedEventOnTimelineArgs { + pinnedEventId?: Maybe, + eventId: Scalars['ID'], + timelineId?: Maybe +} + - defaultIndex: string[]; +export interface MutationDeletePinnedEventOnTimelineArgs { + id: Array } -export interface HostFirstLastSeenSourceArgs { - id?: Maybe; - hostName: string; - defaultIndex: string[]; +export interface MutationDeleteAllPinnedEventsOnTimelineArgs { + timelineId: Scalars['ID'] } -export interface IpOverviewSourceArgs { - id?: Maybe; - filterQuery?: Maybe; - ip: string; +export interface MutationPersistTimelineArgs { + id?: Maybe, + version?: Maybe, + timeline: TimelineInput +} + - defaultIndex: string[]; +export interface MutationPersistFavoriteArgs { + timelineId?: Maybe } -export interface UsersSourceArgs { - filterQuery?: Maybe; - id?: Maybe; - ip: string; +export interface MutationDeleteTimelineArgs { + id: Array +} - pagination: PaginationInputPaginated; +export enum NetworkDirectionEcs { + inbound = 'inbound', + outbound = 'outbound', + internal = 'internal', + external = 'external', + incoming = 'incoming', + outgoing = 'outgoing', + listening = 'listening', + unknown = 'unknown' +} - sort: UsersSortField; +export interface NetworkDnsData { + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, + histogram?: Maybe>, +} - flowTarget: FlowTarget; +export interface NetworkDnsEdges { + node: NetworkDnsItem, + cursor: CursorType, +} - timerange: TimerangeInput; +export enum NetworkDnsFields { + dnsName = 'dnsName', + queryCount = 'queryCount', + uniqueDomains = 'uniqueDomains', + dnsBytesIn = 'dnsBytesIn', + dnsBytesOut = 'dnsBytesOut' +} - defaultIndex: string[]; +export interface NetworkDnsItem { + _id?: Maybe, + dnsBytesIn?: Maybe, + dnsBytesOut?: Maybe, + dnsName?: Maybe, + queryCount?: Maybe, + uniqueDomains?: Maybe, } -export interface KpiNetworkSourceArgs { - id?: Maybe; - timerange: TimerangeInput; +export interface NetworkDnsSortField { + field: NetworkDnsFields, + direction: Direction, +} - filterQuery?: Maybe; +export interface NetworkDsOverTimeData { + inspect?: Maybe, + matrixHistogramData: Array, + totalCount: Scalars['Float'], +} - defaultIndex: string[]; +export interface NetworkEcsField { + bytes?: Maybe, + community_id?: Maybe, + direction?: Maybe, + packets?: Maybe, + protocol?: Maybe, + transport?: Maybe, } -export interface KpiHostsSourceArgs { - id?: Maybe; - timerange: TimerangeInput; +export interface NetworkHttpData { + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +} - filterQuery?: Maybe; +export interface NetworkHttpEdges { + node: NetworkHttpItem, + cursor: CursorType, +} - defaultIndex: string[]; +export enum NetworkHttpFields { + domains = 'domains', + lastHost = 'lastHost', + lastSourceIp = 'lastSourceIp', + methods = 'methods', + path = 'path', + requestCount = 'requestCount', + statuses = 'statuses' } -export interface KpiHostDetailsSourceArgs { - id?: Maybe; - timerange: TimerangeInput; +export interface NetworkHttpItem { + _id?: Maybe, + domains: Array, + lastHost?: Maybe, + lastSourceIp?: Maybe, + methods: Array, + path?: Maybe, + requestCount?: Maybe, + statuses: Array, +} - filterQuery?: Maybe; +export interface NetworkHttpSortField { + direction: Direction, +} - defaultIndex: string[]; +export interface NetworkTopCountriesData { + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, } -export interface MatrixHistogramSourceArgs { - filterQuery?: Maybe; - defaultIndex: string[]; +export interface NetworkTopCountriesEdges { + node: NetworkTopCountriesItem, + cursor: CursorType, +} - timerange: TimerangeInput; +export interface NetworkTopCountriesItem { + _id?: Maybe, + source?: Maybe, + destination?: Maybe, + network?: Maybe, +} - stackByField: string; +export interface NetworkTopNFlowData { + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +} - histogramType: HistogramType; +export interface NetworkTopNFlowEdges { + node: NetworkTopNFlowItem, + cursor: CursorType, } -export interface NetworkTopCountriesSourceArgs { - id?: Maybe; - filterQuery?: Maybe; +export interface NetworkTopNFlowItem { + _id?: Maybe, + source?: Maybe, + destination?: Maybe, + network?: Maybe, +} - ip?: Maybe; +export enum NetworkTopTablesFields { + bytes_in = 'bytes_in', + bytes_out = 'bytes_out', + flows = 'flows', + destination_ips = 'destination_ips', + source_ips = 'source_ips' +} - flowTarget: FlowTargetSourceDest; +export interface NetworkTopTablesSortField { + field: NetworkTopTablesFields, + direction: Direction, +} - pagination: PaginationInputPaginated; +export interface NoteInput { + eventId?: Maybe, + note?: Maybe, + timelineId?: Maybe, +} - sort: NetworkTopTablesSortField; +export interface NoteResult { + eventId?: Maybe, + note?: Maybe, + timelineId?: Maybe, + noteId: Scalars['String'], + created?: Maybe, + createdBy?: Maybe, + timelineVersion?: Maybe, + updated?: Maybe, + updatedBy?: Maybe, + version?: Maybe, +} - timerange: TimerangeInput; +export interface OsEcsFields { + platform?: Maybe, + name?: Maybe, + full?: Maybe, + family?: Maybe, + version?: Maybe, + kernel?: Maybe, +} - defaultIndex: string[]; +export interface OsFields { + platform?: Maybe, + name?: Maybe, + full?: Maybe, + family?: Maybe, + version?: Maybe, + kernel?: Maybe, } -export interface NetworkTopNFlowSourceArgs { - id?: Maybe; - filterQuery?: Maybe; +export interface Overview { + firstSeen?: Maybe, + lastSeen?: Maybe, + autonomousSystem: AutonomousSystem, + geo: GeoEcsFields, +} - ip?: Maybe; +export interface OverviewHostData { + auditbeatAuditd?: Maybe, + auditbeatFIM?: Maybe, + auditbeatLogin?: Maybe, + auditbeatPackage?: Maybe, + auditbeatProcess?: Maybe, + auditbeatUser?: Maybe, + endgameDns?: Maybe, + endgameFile?: Maybe, + endgameImageLoad?: Maybe, + endgameNetwork?: Maybe, + endgameProcess?: Maybe, + endgameRegistry?: Maybe, + endgameSecurity?: Maybe, + filebeatSystemModule?: Maybe, + winlogbeatSecurity?: Maybe, + winlogbeatMWSysmonOperational?: Maybe, + inspect?: Maybe, +} - flowTarget: FlowTargetSourceDest; +export interface OverviewNetworkData { + auditbeatSocket?: Maybe, + filebeatCisco?: Maybe, + filebeatNetflow?: Maybe, + filebeatPanw?: Maybe, + filebeatSuricata?: Maybe, + filebeatZeek?: Maybe, + packetbeatDNS?: Maybe, + packetbeatFlow?: Maybe, + packetbeatTLS?: Maybe, + inspect?: Maybe, +} - pagination: PaginationInputPaginated; +export interface PackageEcsFields { + arch?: Maybe, + entity_id?: Maybe, + name?: Maybe, + size?: Maybe, + summary?: Maybe, + version?: Maybe, +} - sort: NetworkTopTablesSortField; +export interface PageInfo { + endCursor?: Maybe, + hasNextPage?: Maybe, +} - timerange: TimerangeInput; +export interface PageInfoNote { + pageIndex: Scalars['Float'], + pageSize: Scalars['Float'], +} - defaultIndex: string[]; +export interface PageInfoPaginated { + activePage: Scalars['Float'], + fakeTotalCount: Scalars['Float'], + showMorePagesIndicator: Scalars['Boolean'], } -export interface NetworkDnsSourceArgs { - filterQuery?: Maybe; - id?: Maybe; +export interface PageInfoTimeline { + pageIndex: Scalars['Float'], + pageSize: Scalars['Float'], +} - isPtrIncluded: boolean; +export interface PaginationInput { + /** The limit parameter allows you to configure the maximum amount of items to be returned */ + limit: Scalars['Float'], + /** The cursor parameter defines the next result you want to fetch */ + cursor?: Maybe, + /** The tiebreaker parameter allow to be more precise to fetch the next item */ + tiebreaker?: Maybe, +} - pagination: PaginationInputPaginated; +export interface PaginationInputPaginated { + /** The activePage parameter defines the page of results you want to fetch */ + activePage: Scalars['Float'], + /** The cursorStart parameter defines the start of the results to be displayed */ + cursorStart: Scalars['Float'], + /** The fakePossibleCount parameter determines the total count in order to show 5 additional pages */ + fakePossibleCount: Scalars['Float'], + /** The querySize parameter is the number of items to be returned */ + querySize: Scalars['Float'], +} - sort: NetworkDnsSortField; +export interface PinnedEvent { + code?: Maybe, + message?: Maybe, + pinnedEventId: Scalars['ID'], + eventId?: Maybe, + timelineId?: Maybe, + timelineVersion?: Maybe, + created?: Maybe, + createdBy?: Maybe, + updated?: Maybe, + updatedBy?: Maybe, + version?: Maybe, +} - stackByField?: Maybe; +export interface PrimarySecondary { + primary?: Maybe, + secondary?: Maybe, + type?: Maybe, +} - timerange: TimerangeInput; +export interface ProcessEcsFields { + hash?: Maybe, + pid?: Maybe, + name?: Maybe, + ppid?: Maybe, + args?: Maybe, + executable?: Maybe, + title?: Maybe, + thread?: Maybe, + working_directory?: Maybe, +} - defaultIndex: string[]; +export interface ProcessHashData { + md5?: Maybe, + sha1?: Maybe, + sha256?: Maybe, } -export interface NetworkDnsHistogramSourceArgs { - filterQuery?: Maybe; - defaultIndex: string[]; +export interface Query { + getNote: NoteResult, + getNotesByTimelineId: Array, + getNotesByEventId: Array, + getAllNotes: ResponseNotes, + getAllPinnedEventsByTimelineId: Array, + /** Get a security data source by id */ + source: Source, + /** Get a list of all security data sources */ + allSources: Array, + getOneTimeline: TimelineResult, + getAllTimeline: ResponseTimelines, +} - timerange: TimerangeInput; - stackByField?: Maybe; +export interface QueryGetNoteArgs { + id: Scalars['ID'] } -export interface NetworkHttpSourceArgs { - id?: Maybe; - filterQuery?: Maybe; - ip?: Maybe; +export interface QueryGetNotesByTimelineIdArgs { + timelineId: Scalars['ID'] +} - pagination: PaginationInputPaginated; - sort: NetworkHttpSortField; +export interface QueryGetNotesByEventIdArgs { + eventId: Scalars['ID'] +} - timerange: TimerangeInput; - defaultIndex: string[]; +export interface QueryGetAllNotesArgs { + pageInfo?: Maybe, + search?: Maybe, + sort?: Maybe } -export interface OverviewNetworkSourceArgs { - id?: Maybe; - - timerange: TimerangeInput; - filterQuery?: Maybe; - defaultIndex: string[]; +export interface QueryGetAllPinnedEventsByTimelineIdArgs { + timelineId: Scalars['ID'] } -export interface OverviewHostSourceArgs { - id?: Maybe; - timerange: TimerangeInput; - filterQuery?: Maybe; - - defaultIndex: string[]; +export interface QuerySourceArgs { + id: Scalars['ID'] } -export interface TlsSourceArgs { - filterQuery?: Maybe; - - id?: Maybe; - ip: string; - pagination: PaginationInputPaginated; +export interface QueryGetOneTimelineArgs { + id: Scalars['ID'] +} - sort: TlsSortField; - flowTarget: FlowTargetSourceDest; +export interface QueryGetAllTimelineArgs { + pageInfo?: Maybe, + search?: Maybe, + sort?: Maybe, + onlyUserFavorite?: Maybe +} - timerange: TimerangeInput; +export interface QueryMatchInput { + field?: Maybe, + displayField?: Maybe, + value?: Maybe, + displayValue?: Maybe, + operator?: Maybe, +} - defaultIndex: string[]; +export interface QueryMatchResult { + field?: Maybe, + displayField?: Maybe, + value?: Maybe, + displayValue?: Maybe, + operator?: Maybe, } -export interface UncommonProcessesSourceArgs { - timerange: TimerangeInput; - pagination: PaginationInputPaginated; +export interface ResponseFavoriteTimeline { + code?: Maybe, + message?: Maybe, + savedObjectId: Scalars['String'], + version: Scalars['String'], + favorite?: Maybe>, +} - filterQuery?: Maybe; +export interface ResponseNote { + code?: Maybe, + message?: Maybe, + note: NoteResult, +} - defaultIndex: string[]; +export interface ResponseNotes { + notes: Array, + totalCount?: Maybe, } -export interface IndicesExistSourceStatusArgs { - defaultIndex: string[]; + +export interface ResponseTimeline { + code?: Maybe, + message?: Maybe, + timeline: TimelineResult, } -export interface IndexFieldsSourceStatusArgs { - defaultIndex: string[]; + +export interface ResponseTimelines { + timeline: Array>, + totalCount?: Maybe, } -export interface PersistNoteMutationArgs { - noteId?: Maybe; - version?: Maybe; +export interface RuleEcsField { + reference?: Maybe, +} - note: NoteInput; +export interface RuleField { + id?: Maybe, + rule_id?: Maybe, + false_positives: Array, + saved_id?: Maybe, + timeline_id?: Maybe, + timeline_title?: Maybe, + max_signals?: Maybe, + risk_score?: Maybe, + output_index?: Maybe, + description?: Maybe, + from?: Maybe, + immutable?: Maybe, + index?: Maybe, + interval?: Maybe, + language?: Maybe, + query?: Maybe, + references?: Maybe, + severity?: Maybe, + tags?: Maybe, + threat?: Maybe, + type?: Maybe, + size?: Maybe, + to?: Maybe, + enabled?: Maybe, + filters?: Maybe, + created_at?: Maybe, + updated_at?: Maybe, + created_by?: Maybe, + updated_by?: Maybe, + version?: Maybe, } -export interface DeleteNoteMutationArgs { - id: string[]; + +export interface SayMyName { + /** The id of the source */ + appName: Scalars['String'], } -export interface DeleteNoteByTimelineIdMutationArgs { - timelineId: string; - version?: Maybe; +export interface SerializedFilterQueryInput { + filterQuery?: Maybe, } -export interface PersistPinnedEventOnTimelineMutationArgs { - pinnedEventId?: Maybe; - eventId: string; +export interface SerializedFilterQueryResult { + filterQuery?: Maybe, +} - timelineId?: Maybe; +export interface SerializedKueryQueryInput { + kuery?: Maybe, + serializedQuery?: Maybe, } -export interface DeletePinnedEventOnTimelineMutationArgs { - id: string[]; + +export interface SerializedKueryQueryResult { + kuery?: Maybe, + serializedQuery?: Maybe, } -export interface DeleteAllPinnedEventsOnTimelineMutationArgs { - timelineId: string; + +export interface SignalField { + rule?: Maybe, + original_time?: Maybe, } -export interface PersistTimelineMutationArgs { - id?: Maybe; - version?: Maybe; +export interface SortField { + sortFieldId: Scalars['String'], + direction: Direction, +} - timeline: TimelineInput; +export enum SortFieldNote { + updatedBy = 'updatedBy', + updated = 'updated' } -export interface PersistFavoriteMutationArgs { - timelineId?: Maybe; + +export enum SortFieldTimeline { + title = 'title', + description = 'description', + updated = 'updated', + created = 'created' } -export interface DeleteTimelineMutationArgs { - id: string[]; + +export interface SortNote { + sortField: SortFieldNote, + sortOrder: Direction, } -import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'; +export interface SortTimeline { + sortField: SortFieldTimeline, + sortOrder: Direction, +} -export type Resolver = ( - parent: Parent, - args: Args, - context: TContext, - info: GraphQLResolveInfo -) => Promise | Result; - -export interface ISubscriptionResolverObject { - subscribe( - parent: P, - args: Args, - context: TContext, - info: GraphQLResolveInfo - ): AsyncIterator | Promise>; - resolve?( - parent: P, - args: Args, - context: TContext, - info: GraphQLResolveInfo - ): R | Result | Promise; -} - -export type SubscriptionResolver = - | ((...args: any[]) => ISubscriptionResolverObject) - | ISubscriptionResolverObject; - -export type TypeResolveFn = ( - parent: Parent, - context: TContext, - info: GraphQLResolveInfo -) => Maybe; +export interface SortTimelineInput { + columnId?: Maybe, + sortDirection?: Maybe, +} -export type NextResolverFn = () => Promise; +export interface SortTimelineResult { + columnId?: Maybe, + sortDirection?: Maybe, +} -export type DirectiveResolverFn = ( - next: NextResolverFn, - source: any, - args: TArgs, - context: TContext, - info: GraphQLResolveInfo -) => TResult | Promise; +export interface Source { + /** The id of the source */ + id: Scalars['ID'], + /** The raw configuration of the source */ + configuration: SourceConfiguration, + /** The status of the source */ + status: SourceStatus, + /** Gets Authentication success and failures based on a timerange */ + Authentications: AuthenticationsData, + Timeline: TimelineData, + TimelineDetails: TimelineDetailsData, + LastEventTime: LastEventTimeData, + /** Gets Hosts based on timerange and specified criteria, or all events in the timerange if no criteria is specified */ + Hosts: HostsData, + HostOverview: HostItem, + HostFirstLastSeen: FirstLastSeenHost, + IpOverview?: Maybe, + Users: UsersData, + KpiNetwork?: Maybe, + KpiHosts: KpiHostsData, + KpiHostDetails: KpiHostDetailsData, + MatrixHistogram: MatrixHistogramOverTimeData, + NetworkTopCountries: NetworkTopCountriesData, + NetworkTopNFlow: NetworkTopNFlowData, + NetworkDns: NetworkDnsData, + NetworkDnsHistogram: NetworkDsOverTimeData, + NetworkHttp: NetworkHttpData, + OverviewNetwork?: Maybe, + OverviewHost?: Maybe, + Tls: TlsData, + /** Gets UncommonProcesses based on a timerange, or all UncommonProcesses if no criteria is specified */ + UncommonProcesses: UncommonProcessesData, + /** Just a simple example to get the app name */ + whoAmI?: Maybe, +} -export namespace QueryResolvers { - export interface Resolvers { - getNote?: GetNoteResolver; - - getNotesByTimelineId?: GetNotesByTimelineIdResolver; - - getNotesByEventId?: GetNotesByEventIdResolver; - - getAllNotes?: GetAllNotesResolver; - - getAllPinnedEventsByTimelineId?: GetAllPinnedEventsByTimelineIdResolver< - PinnedEvent[], - TypeParent, - TContext - >; - /** Get a security data source by id */ - source?: SourceResolver; - /** Get a list of all security data sources */ - allSources?: AllSourcesResolver; - - getOneTimeline?: GetOneTimelineResolver; - - getAllTimeline?: GetAllTimelineResolver; - } - - export type GetNoteResolver = Resolver< - R, - Parent, - TContext, - GetNoteArgs - >; - export interface GetNoteArgs { - id: string; - } - - export type GetNotesByTimelineIdResolver< - R = NoteResult[], - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface GetNotesByTimelineIdArgs { - timelineId: string; - } - - export type GetNotesByEventIdResolver< - R = NoteResult[], - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface GetNotesByEventIdArgs { - eventId: string; - } - - export type GetAllNotesResolver< - R = ResponseNotes, - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface GetAllNotesArgs { - pageInfo?: Maybe; - - search?: Maybe; - - sort?: Maybe; - } - - export type GetAllPinnedEventsByTimelineIdResolver< - R = PinnedEvent[], - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface GetAllPinnedEventsByTimelineIdArgs { - timelineId: string; - } - - export type SourceResolver = Resolver< - R, - Parent, - TContext, - SourceArgs - >; - export interface SourceArgs { - /** The id of the source */ - id: string; - } - - export type AllSourcesResolver = Resolver< - R, - Parent, - TContext - >; - export type GetOneTimelineResolver< - R = TimelineResult, - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface GetOneTimelineArgs { - id: string; - } - - export type GetAllTimelineResolver< - R = ResponseTimelines, - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface GetAllTimelineArgs { - pageInfo?: Maybe; - - search?: Maybe; - - sort?: Maybe; - - onlyUserFavorite?: Maybe; - } -} - -export namespace NoteResultResolvers { - export interface Resolvers { - eventId?: EventIdResolver, TypeParent, TContext>; - - note?: NoteResolver, TypeParent, TContext>; - - timelineId?: TimelineIdResolver, TypeParent, TContext>; - - noteId?: NoteIdResolver; - - created?: CreatedResolver, TypeParent, TContext>; - - createdBy?: CreatedByResolver, TypeParent, TContext>; - - timelineVersion?: TimelineVersionResolver, TypeParent, TContext>; - - updated?: UpdatedResolver, TypeParent, TContext>; - - updatedBy?: UpdatedByResolver, TypeParent, TContext>; - - version?: VersionResolver, TypeParent, TContext>; - } - - export type EventIdResolver< - R = Maybe, - Parent = NoteResult, - TContext = SiemContext - > = Resolver; - export type NoteResolver< - R = Maybe, - Parent = NoteResult, - TContext = SiemContext - > = Resolver; - export type TimelineIdResolver< - R = Maybe, - Parent = NoteResult, - TContext = SiemContext - > = Resolver; - export type NoteIdResolver = Resolver< - R, - Parent, - TContext - >; - export type CreatedResolver< - R = Maybe, - Parent = NoteResult, - TContext = SiemContext - > = Resolver; - export type CreatedByResolver< - R = Maybe, - Parent = NoteResult, - TContext = SiemContext - > = Resolver; - export type TimelineVersionResolver< - R = Maybe, - Parent = NoteResult, - TContext = SiemContext - > = Resolver; - export type UpdatedResolver< - R = Maybe, - Parent = NoteResult, - TContext = SiemContext - > = Resolver; - export type UpdatedByResolver< - R = Maybe, - Parent = NoteResult, - TContext = SiemContext - > = Resolver; - export type VersionResolver< - R = Maybe, - Parent = NoteResult, - TContext = SiemContext - > = Resolver; -} - -export namespace ResponseNotesResolvers { - export interface Resolvers { - notes?: NotesResolver; - - totalCount?: TotalCountResolver, TypeParent, TContext>; - } - - export type NotesResolver< - R = NoteResult[], - Parent = ResponseNotes, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver< - R = Maybe, - Parent = ResponseNotes, - TContext = SiemContext - > = Resolver; -} - -export namespace PinnedEventResolvers { - export interface Resolvers { - code?: CodeResolver, TypeParent, TContext>; - - message?: MessageResolver, TypeParent, TContext>; - - pinnedEventId?: PinnedEventIdResolver; - - eventId?: EventIdResolver, TypeParent, TContext>; - - timelineId?: TimelineIdResolver, TypeParent, TContext>; - - timelineVersion?: TimelineVersionResolver, TypeParent, TContext>; - - created?: CreatedResolver, TypeParent, TContext>; - - createdBy?: CreatedByResolver, TypeParent, TContext>; - - updated?: UpdatedResolver, TypeParent, TContext>; - - updatedBy?: UpdatedByResolver, TypeParent, TContext>; - - version?: VersionResolver, TypeParent, TContext>; - } - - export type CodeResolver< - R = Maybe, - Parent = PinnedEvent, - TContext = SiemContext - > = Resolver; - export type MessageResolver< - R = Maybe, - Parent = PinnedEvent, - TContext = SiemContext - > = Resolver; - export type PinnedEventIdResolver< - R = string, - Parent = PinnedEvent, - TContext = SiemContext - > = Resolver; - export type EventIdResolver< - R = Maybe, - Parent = PinnedEvent, - TContext = SiemContext - > = Resolver; - export type TimelineIdResolver< - R = Maybe, - Parent = PinnedEvent, - TContext = SiemContext - > = Resolver; - export type TimelineVersionResolver< - R = Maybe, - Parent = PinnedEvent, - TContext = SiemContext - > = Resolver; - export type CreatedResolver< - R = Maybe, - Parent = PinnedEvent, - TContext = SiemContext - > = Resolver; - export type CreatedByResolver< - R = Maybe, - Parent = PinnedEvent, - TContext = SiemContext - > = Resolver; - export type UpdatedResolver< - R = Maybe, - Parent = PinnedEvent, - TContext = SiemContext - > = Resolver; - export type UpdatedByResolver< - R = Maybe, - Parent = PinnedEvent, - TContext = SiemContext - > = Resolver; - export type VersionResolver< - R = Maybe, - Parent = PinnedEvent, - TContext = SiemContext - > = Resolver; -} - -export namespace SourceResolvers { - export interface Resolvers { - /** The id of the source */ - id?: IdResolver; - /** The raw configuration of the source */ - configuration?: ConfigurationResolver; - /** The status of the source */ - status?: StatusResolver; - /** Gets Authentication success and failures based on a timerange */ - Authentications?: AuthenticationsResolver; - - Timeline?: TimelineResolver; - - TimelineDetails?: TimelineDetailsResolver; - - LastEventTime?: LastEventTimeResolver; - /** Gets Hosts based on timerange and specified criteria, or all events in the timerange if no criteria is specified */ - Hosts?: HostsResolver; - - HostOverview?: HostOverviewResolver; - - HostFirstLastSeen?: HostFirstLastSeenResolver; - - IpOverview?: IpOverviewResolver, TypeParent, TContext>; - - Users?: UsersResolver; - - KpiNetwork?: KpiNetworkResolver, TypeParent, TContext>; - - KpiHosts?: KpiHostsResolver; - - KpiHostDetails?: KpiHostDetailsResolver; - - MatrixHistogram?: MatrixHistogramResolver; - - NetworkTopCountries?: NetworkTopCountriesResolver< - NetworkTopCountriesData, - TypeParent, - TContext - >; - - NetworkTopNFlow?: NetworkTopNFlowResolver; - - NetworkDns?: NetworkDnsResolver; - - NetworkDnsHistogram?: NetworkDnsHistogramResolver; - - NetworkHttp?: NetworkHttpResolver; - - OverviewNetwork?: OverviewNetworkResolver, TypeParent, TContext>; - - OverviewHost?: OverviewHostResolver, TypeParent, TContext>; - - Tls?: TlsResolver; - /** Gets UncommonProcesses based on a timerange, or all UncommonProcesses if no criteria is specified */ - UncommonProcesses?: UncommonProcessesResolver; - /** Just a simple example to get the app name */ - whoAmI?: WhoAmIResolver, TypeParent, TContext>; - } - - export type IdResolver = Resolver< - R, - Parent, - TContext - >; - export type ConfigurationResolver< - R = SourceConfiguration, - Parent = Source, - TContext = SiemContext - > = Resolver; - export type StatusResolver = Resolver< - R, - Parent, - TContext - >; - export type AuthenticationsResolver< - R = AuthenticationsData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface AuthenticationsArgs { - timerange: TimerangeInput; - pagination: PaginationInputPaginated; +export interface SourceAuthenticationsArgs { + timerange: TimerangeInput, + pagination: PaginationInputPaginated, + filterQuery?: Maybe, + defaultIndex: Array +} - filterQuery?: Maybe; - defaultIndex: string[]; - } +export interface SourceTimelineArgs { + pagination: PaginationInput, + sortField: SortField, + fieldRequested: Array, + timerange?: Maybe, + filterQuery?: Maybe, + defaultIndex: Array +} - export type TimelineResolver< - R = TimelineData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface TimelineArgs { - pagination: PaginationInput; - sortField: SortField; +export interface SourceTimelineDetailsArgs { + eventId: Scalars['String'], + indexName: Scalars['String'], + defaultIndex: Array +} - fieldRequested: string[]; - timerange?: Maybe; +export interface SourceLastEventTimeArgs { + id?: Maybe, + indexKey: LastEventIndexKey, + details: LastTimeDetails, + defaultIndex: Array +} - filterQuery?: Maybe; - defaultIndex: string[]; - } +export interface SourceHostsArgs { + id?: Maybe, + timerange: TimerangeInput, + pagination: PaginationInputPaginated, + sort: HostsSortField, + filterQuery?: Maybe, + defaultIndex: Array +} - export type TimelineDetailsResolver< - R = TimelineDetailsData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface TimelineDetailsArgs { - eventId: string; - indexName: string; +export interface SourceHostOverviewArgs { + id?: Maybe, + hostName: Scalars['String'], + timerange: TimerangeInput, + defaultIndex: Array +} - defaultIndex: string[]; - } - export type LastEventTimeResolver< - R = LastEventTimeData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface LastEventTimeArgs { - id?: Maybe; +export interface SourceHostFirstLastSeenArgs { + id?: Maybe, + hostName: Scalars['String'], + defaultIndex: Array +} - indexKey: LastEventIndexKey; - details: LastTimeDetails; +export interface SourceIpOverviewArgs { + id?: Maybe, + filterQuery?: Maybe, + ip: Scalars['String'], + defaultIndex: Array +} - defaultIndex: string[]; - } - export type HostsResolver = Resolver< - R, - Parent, - TContext, - HostsArgs - >; - export interface HostsArgs { - id?: Maybe; +export interface SourceUsersArgs { + filterQuery?: Maybe, + id?: Maybe, + ip: Scalars['String'], + pagination: PaginationInputPaginated, + sort: UsersSortField, + flowTarget: FlowTarget, + timerange: TimerangeInput, + defaultIndex: Array +} - timerange: TimerangeInput; - pagination: PaginationInputPaginated; +export interface SourceKpiNetworkArgs { + id?: Maybe, + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array +} - sort: HostsSortField; - filterQuery?: Maybe; +export interface SourceKpiHostsArgs { + id?: Maybe, + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array +} - defaultIndex: string[]; - } - export type HostOverviewResolver< - R = HostItem, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface HostOverviewArgs { - id?: Maybe; +export interface SourceKpiHostDetailsArgs { + id?: Maybe, + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array +} - hostName: string; - timerange: TimerangeInput; +export interface SourceMatrixHistogramArgs { + filterQuery?: Maybe, + defaultIndex: Array, + timerange: TimerangeInput, + stackByField: Scalars['String'], + histogramType: HistogramType +} - defaultIndex: string[]; - } - export type HostFirstLastSeenResolver< - R = FirstLastSeenHost, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface HostFirstLastSeenArgs { - id?: Maybe; +export interface SourceNetworkTopCountriesArgs { + id?: Maybe, + filterQuery?: Maybe, + ip?: Maybe, + flowTarget: FlowTargetSourceDest, + pagination: PaginationInputPaginated, + sort: NetworkTopTablesSortField, + timerange: TimerangeInput, + defaultIndex: Array +} - hostName: string; - defaultIndex: string[]; - } +export interface SourceNetworkTopNFlowArgs { + id?: Maybe, + filterQuery?: Maybe, + ip?: Maybe, + flowTarget: FlowTargetSourceDest, + pagination: PaginationInputPaginated, + sort: NetworkTopTablesSortField, + timerange: TimerangeInput, + defaultIndex: Array +} - export type IpOverviewResolver< - R = Maybe, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface IpOverviewArgs { - id?: Maybe; - filterQuery?: Maybe; +export interface SourceNetworkDnsArgs { + filterQuery?: Maybe, + id?: Maybe, + isPtrIncluded: Scalars['Boolean'], + pagination: PaginationInputPaginated, + sort: NetworkDnsSortField, + stackByField?: Maybe, + timerange: TimerangeInput, + defaultIndex: Array +} - ip: string; - defaultIndex: string[]; - } +export interface SourceNetworkDnsHistogramArgs { + filterQuery?: Maybe, + defaultIndex: Array, + timerange: TimerangeInput, + stackByField?: Maybe +} - export type UsersResolver = Resolver< - R, - Parent, - TContext, - UsersArgs - >; - export interface UsersArgs { - filterQuery?: Maybe; - id?: Maybe; +export interface SourceNetworkHttpArgs { + id?: Maybe, + filterQuery?: Maybe, + ip?: Maybe, + pagination: PaginationInputPaginated, + sort: NetworkHttpSortField, + timerange: TimerangeInput, + defaultIndex: Array +} - ip: string; - pagination: PaginationInputPaginated; +export interface SourceOverviewNetworkArgs { + id?: Maybe, + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array +} - sort: UsersSortField; - flowTarget: FlowTarget; +export interface SourceOverviewHostArgs { + id?: Maybe, + timerange: TimerangeInput, + filterQuery?: Maybe, + defaultIndex: Array +} - timerange: TimerangeInput; - defaultIndex: string[]; - } +export interface SourceTlsArgs { + filterQuery?: Maybe, + id?: Maybe, + ip: Scalars['String'], + pagination: PaginationInputPaginated, + sort: TlsSortField, + flowTarget: FlowTargetSourceDest, + timerange: TimerangeInput, + defaultIndex: Array +} - export type KpiNetworkResolver< - R = Maybe, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface KpiNetworkArgs { - id?: Maybe; - timerange: TimerangeInput; +export interface SourceUncommonProcessesArgs { + timerange: TimerangeInput, + pagination: PaginationInputPaginated, + filterQuery?: Maybe, + defaultIndex: Array +} - filterQuery?: Maybe; +/** A set of configuration options for a security data source */ +export interface SourceConfiguration { + /** The field mapping to use for this source */ + fields: SourceFields, +} - defaultIndex: string[]; - } +export interface SourceEcsFields { + bytes?: Maybe, + ip?: Maybe, + port?: Maybe, + domain?: Maybe, + geo?: Maybe, + packets?: Maybe, +} - export type KpiHostsResolver< - R = KpiHostsData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface KpiHostsArgs { - id?: Maybe; +/** A mapping of semantic fields to their document counterparts */ +export interface SourceFields { + /** The field to identify a container by */ + container: Scalars['String'], + /** The fields to identify a host by */ + host: Scalars['String'], + /** The fields that may contain the log event message. The first field found win. */ + message: Array, + /** The field to identify a pod by */ + pod: Scalars['String'], + /** The field to use as a tiebreaker for log events that have identical timestamps */ + tiebreaker: Scalars['String'], + /** The field to use as a timestamp for metrics and logs */ + timestamp: Scalars['String'], +} - timerange: TimerangeInput; +/** The status of an infrastructure data source */ +export interface SourceStatus { + /** Whether the configured alias or wildcard pattern resolve to any auditbeat indices */ + indicesExist: Scalars['Boolean'], + /** The list of fields defined in the index mappings */ + indexFields: Array, +} - filterQuery?: Maybe; - defaultIndex: string[]; - } +/** The status of an infrastructure data source */ +export interface SourceStatusIndicesExistArgs { + defaultIndex: Array +} - export type KpiHostDetailsResolver< - R = KpiHostDetailsData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface KpiHostDetailsArgs { - id?: Maybe; - timerange: TimerangeInput; +/** The status of an infrastructure data source */ +export interface SourceStatusIndexFieldsArgs { + defaultIndex: Array +} - filterQuery?: Maybe; +export interface SshEcsFields { + method?: Maybe, + signature?: Maybe, +} - defaultIndex: string[]; - } +export interface Summary { + actor?: Maybe, + object?: Maybe, + how?: Maybe, + message_type?: Maybe, + sequence?: Maybe, +} - export type MatrixHistogramResolver< - R = MatrixHistogramOverTimeData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface MatrixHistogramArgs { - filterQuery?: Maybe; +export interface SuricataAlertData { + signature?: Maybe, + signature_id?: Maybe, +} - defaultIndex: string[]; +export interface SuricataEcsFields { + eve?: Maybe, +} - timerange: TimerangeInput; +export interface SuricataEveData { + alert?: Maybe, + flow_id?: Maybe, + proto?: Maybe, +} - stackByField: string; +export interface SystemEcsField { + audit?: Maybe, + auth?: Maybe, +} - histogramType: HistogramType; - } +export interface Thread { + id?: Maybe, + start?: Maybe, +} - export type NetworkTopCountriesResolver< - R = NetworkTopCountriesData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface NetworkTopCountriesArgs { - id?: Maybe; +export interface TimelineData { + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfo, + inspect?: Maybe, +} - filterQuery?: Maybe; +export interface TimelineDetailsData { + data?: Maybe>, + inspect?: Maybe, +} - ip?: Maybe; +export interface TimelineEdges { + node: TimelineItem, + cursor: CursorType, +} - flowTarget: FlowTargetSourceDest; +export interface TimelineInput { + columns?: Maybe>, + dataProviders?: Maybe>, + description?: Maybe, + eventType?: Maybe, + filters?: Maybe>, + kqlMode?: Maybe, + kqlQuery?: Maybe, + title?: Maybe, + dateRange?: Maybe, + savedQueryId?: Maybe, + sort?: Maybe, +} - pagination: PaginationInputPaginated; +export interface TimelineItem { + _id: Scalars['String'], + _index?: Maybe, + data: Array, + ecs: Ecs, +} - sort: NetworkTopTablesSortField; +export interface TimelineNonEcsData { + field: Scalars['String'], + value?: Maybe, +} - timerange: TimerangeInput; +export interface TimelineResult { + columns?: Maybe>, + created?: Maybe, + createdBy?: Maybe, + dataProviders?: Maybe>, + dateRange?: Maybe, + description?: Maybe, + eventIdToNoteIds?: Maybe>, + eventType?: Maybe, + favorite?: Maybe>, + filters?: Maybe>, + kqlMode?: Maybe, + kqlQuery?: Maybe, + notes?: Maybe>, + noteIds?: Maybe>, + pinnedEventIds?: Maybe>, + pinnedEventsSaveObject?: Maybe>, + savedQueryId?: Maybe, + savedObjectId: Scalars['String'], + sort?: Maybe, + title?: Maybe, + updated?: Maybe, + updatedBy?: Maybe, + version: Scalars['String'], +} - defaultIndex: string[]; - } +export interface TimerangeInput { + /** + * The interval string to use for last bucket. The format is '{value}{unit}'. For + * example '5m' would return the metrics for the last 5 minutes of the timespan. + */ + interval: Scalars['String'], + /** The end of the timerange */ + to: Scalars['Float'], + /** The beginning of the timerange */ + from: Scalars['Float'], +} - export type NetworkTopNFlowResolver< - R = NetworkTopNFlowData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface NetworkTopNFlowArgs { - id?: Maybe; +export interface TlsClientCertificateData { + fingerprint?: Maybe, +} - filterQuery?: Maybe; +export interface TlsData { + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +} - ip?: Maybe; +export interface TlsEcsFields { + client_certificate?: Maybe, + fingerprints?: Maybe, + server_certificate?: Maybe, +} - flowTarget: FlowTargetSourceDest; +export interface TlsEdges { + node: TlsNode, + cursor: CursorType, +} - pagination: PaginationInputPaginated; +export enum TlsFields { + _id = '_id' +} - sort: NetworkTopTablesSortField; +export interface TlsFingerprintsData { + ja3?: Maybe, +} - timerange: TimerangeInput; +export interface TlsJa3Data { + hash?: Maybe, +} - defaultIndex: string[]; - } +export interface TlsNode { + _id?: Maybe, + timestamp?: Maybe, + alternativeNames?: Maybe>, + notAfter?: Maybe>, + commonNames?: Maybe>, + ja3?: Maybe>, + issuerNames?: Maybe>, +} - export type NetworkDnsResolver< - R = NetworkDnsData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface NetworkDnsArgs { - filterQuery?: Maybe; +export interface TlsServerCertificateData { + fingerprint?: Maybe, +} - id?: Maybe; +export interface TlsSortField { + field: TlsFields, + direction: Direction, +} - isPtrIncluded: boolean; - pagination: PaginationInputPaginated; - sort: NetworkDnsSortField; - stackByField?: Maybe; - timerange: TimerangeInput; +export interface TopCountriesItemDestination { + country?: Maybe, + destination_ips?: Maybe, + flows?: Maybe, + location?: Maybe, + source_ips?: Maybe, +} - defaultIndex: string[]; - } +export interface TopCountriesItemSource { + country?: Maybe, + destination_ips?: Maybe, + flows?: Maybe, + location?: Maybe, + source_ips?: Maybe, +} - export type NetworkDnsHistogramResolver< - R = NetworkDsOverTimeData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface NetworkDnsHistogramArgs { - filterQuery?: Maybe; +export interface TopNetworkTablesEcsField { + bytes_in?: Maybe, + bytes_out?: Maybe, +} - defaultIndex: string[]; +export interface TopNFlowItemDestination { + autonomous_system?: Maybe, + domain?: Maybe>, + ip?: Maybe, + location?: Maybe, + flows?: Maybe, + source_ips?: Maybe, +} - timerange: TimerangeInput; +export interface TopNFlowItemSource { + autonomous_system?: Maybe, + domain?: Maybe>, + ip?: Maybe, + location?: Maybe, + flows?: Maybe, + destination_ips?: Maybe, +} - stackByField?: Maybe; - } - export type NetworkHttpResolver< - R = NetworkHttpData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface NetworkHttpArgs { - id?: Maybe; +export interface UncommonProcessesData { + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +} - filterQuery?: Maybe; +export interface UncommonProcessesEdges { + node: UncommonProcessItem, + cursor: CursorType, +} - ip?: Maybe; +export interface UncommonProcessItem { + _id: Scalars['String'], + instances: Scalars['Float'], + process: ProcessEcsFields, + hosts: Array, + user?: Maybe, +} - pagination: PaginationInputPaginated; +export interface UrlEcsFields { + domain?: Maybe, + original?: Maybe, + username?: Maybe, + password?: Maybe, +} - sort: NetworkHttpSortField; +export interface UserEcsFields { + domain?: Maybe, + id?: Maybe, + name?: Maybe, + full_name?: Maybe, + email?: Maybe, + hash?: Maybe, + group?: Maybe, +} - timerange: TimerangeInput; +export interface UsersData { + edges: Array, + totalCount: Scalars['Float'], + pageInfo: PageInfoPaginated, + inspect?: Maybe, +} - defaultIndex: string[]; - } +export interface UsersEdges { + node: UsersNode, + cursor: CursorType, +} - export type OverviewNetworkResolver< - R = Maybe, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface OverviewNetworkArgs { - id?: Maybe; +export enum UsersFields { + name = 'name', + count = 'count' +} - timerange: TimerangeInput; +export interface UsersItem { + name?: Maybe, + id?: Maybe, + groupId?: Maybe, + groupName?: Maybe, + count?: Maybe, +} - filterQuery?: Maybe; +export interface UsersNode { + _id?: Maybe, + timestamp?: Maybe, + user?: Maybe, +} - defaultIndex: string[]; - } +export interface UsersSortField { + field: UsersFields, + direction: Direction, +} - export type OverviewHostResolver< - R = Maybe, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface OverviewHostArgs { - id?: Maybe; +export interface WinlogEcsFields { + event_id?: Maybe, +} - timerange: TimerangeInput; +export interface ZeekConnectionData { + local_resp?: Maybe, + local_orig?: Maybe, + missed_bytes?: Maybe, + state?: Maybe, + history?: Maybe, +} - filterQuery?: Maybe; +export interface ZeekDnsData { + AA?: Maybe, + qclass_name?: Maybe, + RD?: Maybe, + qtype_name?: Maybe, + rejected?: Maybe, + qtype?: Maybe, + query?: Maybe, + trans_id?: Maybe, + qclass?: Maybe, + RA?: Maybe, + TC?: Maybe, +} - defaultIndex: string[]; - } +export interface ZeekEcsFields { + session_id?: Maybe, + connection?: Maybe, + notice?: Maybe, + dns?: Maybe, + http?: Maybe, + files?: Maybe, + ssl?: Maybe, +} - export type TlsResolver = Resolver< - R, - Parent, - TContext, - TlsArgs - >; - export interface TlsArgs { - filterQuery?: Maybe; +export interface ZeekFileData { + session_ids?: Maybe, + timedout?: Maybe, + local_orig?: Maybe, + tx_host?: Maybe, + source?: Maybe, + is_orig?: Maybe, + overflow_bytes?: Maybe, + sha1?: Maybe, + duration?: Maybe, + depth?: Maybe, + analyzers?: Maybe, + mime_type?: Maybe, + rx_host?: Maybe, + total_bytes?: Maybe, + fuid?: Maybe, + seen_bytes?: Maybe, + missing_bytes?: Maybe, + md5?: Maybe, +} - id?: Maybe; +export interface ZeekHttpData { + resp_mime_types?: Maybe, + trans_depth?: Maybe, + status_msg?: Maybe, + resp_fuids?: Maybe, + tags?: Maybe, +} - ip: string; +export interface ZeekNoticeData { + suppress_for?: Maybe, + msg?: Maybe, + note?: Maybe, + sub?: Maybe, + dst?: Maybe, + dropped?: Maybe, + peer_descr?: Maybe, +} - pagination: PaginationInputPaginated; +export interface ZeekSslData { + cipher?: Maybe, + established?: Maybe, + resumed?: Maybe, + version?: Maybe, +} - sort: TlsSortField; +export type WithIndex = TObject & Record; +export type ResolversObject = WithIndex; - flowTarget: FlowTargetSourceDest; +export type ResolverTypeWrapper = Promise | T; - timerange: TimerangeInput; +export type ResolverFn = ( + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => Promise | TResult; - defaultIndex: string[]; - } - export type UncommonProcessesResolver< - R = UncommonProcessesData, - Parent = Source, - TContext = SiemContext - > = Resolver; - export interface UncommonProcessesArgs { - timerange: TimerangeInput; +export type StitchingResolver = { + fragment: string; + resolve: ResolverFn; +}; - pagination: PaginationInputPaginated; +export type Resolver = + | ResolverFn + | StitchingResolver; - filterQuery?: Maybe; +export type SubscriptionSubscribeFn = ( + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => AsyncIterator | Promise>; - defaultIndex: string[]; - } +export type SubscriptionResolveFn = ( + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => TResult | Promise; - export type WhoAmIResolver< - R = Maybe, - Parent = Source, - TContext = SiemContext - > = Resolver; -} -/** A set of configuration options for a security data source */ -export namespace SourceConfigurationResolvers { - export interface Resolvers { - /** The field mapping to use for this source */ - fields?: FieldsResolver; - } - - export type FieldsResolver< - R = SourceFields, - Parent = SourceConfiguration, - TContext = SiemContext - > = Resolver; -} -/** A mapping of semantic fields to their document counterparts */ -export namespace SourceFieldsResolvers { - export interface Resolvers { - /** The field to identify a container by */ - container?: ContainerResolver; - /** The fields to identify a host by */ - host?: HostResolver; - /** The fields that may contain the log event message. The first field found win. */ - message?: MessageResolver; - /** The field to identify a pod by */ - pod?: PodResolver; - /** The field to use as a tiebreaker for log events that have identical timestamps */ - tiebreaker?: TiebreakerResolver; - /** The field to use as a timestamp for metrics and logs */ - timestamp?: TimestampResolver; - } - - export type ContainerResolver< - R = string, - Parent = SourceFields, - TContext = SiemContext - > = Resolver; - export type HostResolver = Resolver< - R, - Parent, - TContext - >; - export type MessageResolver< - R = string[], - Parent = SourceFields, - TContext = SiemContext - > = Resolver; - export type PodResolver = Resolver< - R, - Parent, - TContext - >; - export type TiebreakerResolver< - R = string, - Parent = SourceFields, - TContext = SiemContext - > = Resolver; - export type TimestampResolver< - R = string, - Parent = SourceFields, - TContext = SiemContext - > = Resolver; -} -/** The status of an infrastructure data source */ -export namespace SourceStatusResolvers { - export interface Resolvers { - /** Whether the configured alias or wildcard pattern resolve to any auditbeat indices */ - indicesExist?: IndicesExistResolver; - /** The list of fields defined in the index mappings */ - indexFields?: IndexFieldsResolver; - } - - export type IndicesExistResolver< - R = boolean, - Parent = SourceStatus, - TContext = SiemContext - > = Resolver; - export interface IndicesExistArgs { - defaultIndex: string[]; - } - - export type IndexFieldsResolver< - R = IndexField[], - Parent = SourceStatus, - TContext = SiemContext - > = Resolver; - export interface IndexFieldsArgs { - defaultIndex: string[]; - } +export interface SubscriptionSubscriberObject { + subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>; + resolve?: SubscriptionResolveFn; } -/** A descriptor of a field in an index */ -export namespace IndexFieldResolvers { - export interface Resolvers { - /** Where the field belong */ - category?: CategoryResolver; - /** Example of field's value */ - example?: ExampleResolver, TypeParent, TContext>; - /** whether the field's belong to an alias index */ - indexes?: IndexesResolver<(Maybe)[], TypeParent, TContext>; - /** The name of the field */ - name?: NameResolver; - /** The type of the field's values as recognized by Kibana */ - type?: TypeResolver; - /** Whether the field's values can be efficiently searched for */ - searchable?: SearchableResolver; - /** Whether the field's values can be aggregated */ - aggregatable?: AggregatableResolver; - /** Description of the field */ - description?: DescriptionResolver, TypeParent, TContext>; - - format?: FormatResolver, TypeParent, TContext>; - } - - export type CategoryResolver = Resolver< - R, - Parent, - TContext - >; - export type ExampleResolver< - R = Maybe, - Parent = IndexField, - TContext = SiemContext - > = Resolver; - export type IndexesResolver< - R = (Maybe)[], - Parent = IndexField, - TContext = SiemContext - > = Resolver; - export type NameResolver = Resolver< - R, - Parent, - TContext - >; - export type TypeResolver = Resolver< - R, - Parent, - TContext - >; - export type SearchableResolver< - R = boolean, - Parent = IndexField, - TContext = SiemContext - > = Resolver; - export type AggregatableResolver< - R = boolean, - Parent = IndexField, - TContext = SiemContext - > = Resolver; - export type DescriptionResolver< - R = Maybe, - Parent = IndexField, - TContext = SiemContext - > = Resolver; - export type FormatResolver< - R = Maybe, - Parent = IndexField, - TContext = SiemContext - > = Resolver; -} - -export namespace AuthenticationsDataResolvers { - export interface Resolvers { - edges?: EdgesResolver; - - totalCount?: TotalCountResolver; - - pageInfo?: PageInfoResolver; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type EdgesResolver< - R = AuthenticationsEdges[], - Parent = AuthenticationsData, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver< - R = number, - Parent = AuthenticationsData, - TContext = SiemContext - > = Resolver; - export type PageInfoResolver< - R = PageInfoPaginated, - Parent = AuthenticationsData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = AuthenticationsData, - TContext = SiemContext - > = Resolver; -} - -export namespace AuthenticationsEdgesResolvers { - export interface Resolvers { - node?: NodeResolver; - - cursor?: CursorResolver; - } - - export type NodeResolver< - R = AuthenticationItem, - Parent = AuthenticationsEdges, - TContext = SiemContext - > = Resolver; - export type CursorResolver< - R = CursorType, - Parent = AuthenticationsEdges, - TContext = SiemContext - > = Resolver; -} - -export namespace AuthenticationItemResolvers { - export interface Resolvers { - _id?: _IdResolver; - - failures?: FailuresResolver; - - successes?: SuccessesResolver; - - user?: UserResolver; - - lastSuccess?: LastSuccessResolver, TypeParent, TContext>; - - lastFailure?: LastFailureResolver, TypeParent, TContext>; - } - - export type _IdResolver< - R = string, - Parent = AuthenticationItem, - TContext = SiemContext - > = Resolver; - export type FailuresResolver< - R = number, - Parent = AuthenticationItem, - TContext = SiemContext - > = Resolver; - export type SuccessesResolver< - R = number, - Parent = AuthenticationItem, - TContext = SiemContext - > = Resolver; - export type UserResolver< - R = UserEcsFields, - Parent = AuthenticationItem, - TContext = SiemContext - > = Resolver; - export type LastSuccessResolver< - R = Maybe, - Parent = AuthenticationItem, - TContext = SiemContext - > = Resolver; - export type LastFailureResolver< - R = Maybe, - Parent = AuthenticationItem, - TContext = SiemContext - > = Resolver; -} - -export namespace UserEcsFieldsResolvers { - export interface Resolvers { - domain?: DomainResolver, TypeParent, TContext>; - - id?: IdResolver, TypeParent, TContext>; - - name?: NameResolver, TypeParent, TContext>; - - full_name?: FullNameResolver, TypeParent, TContext>; - - email?: EmailResolver, TypeParent, TContext>; - - hash?: HashResolver, TypeParent, TContext>; - - group?: GroupResolver, TypeParent, TContext>; - } - - export type DomainResolver< - R = Maybe, - Parent = UserEcsFields, - TContext = SiemContext - > = Resolver; - export type IdResolver< - R = Maybe, - Parent = UserEcsFields, - TContext = SiemContext - > = Resolver; - export type NameResolver< - R = Maybe, - Parent = UserEcsFields, - TContext = SiemContext - > = Resolver; - export type FullNameResolver< - R = Maybe, - Parent = UserEcsFields, - TContext = SiemContext - > = Resolver; - export type EmailResolver< - R = Maybe, - Parent = UserEcsFields, - TContext = SiemContext - > = Resolver; - export type HashResolver< - R = Maybe, - Parent = UserEcsFields, - TContext = SiemContext - > = Resolver; - export type GroupResolver< - R = Maybe, - Parent = UserEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace LastSourceHostResolvers { - export interface Resolvers { - timestamp?: TimestampResolver, TypeParent, TContext>; - - source?: SourceResolver, TypeParent, TContext>; - - host?: HostResolver, TypeParent, TContext>; - } - - export type TimestampResolver< - R = Maybe, - Parent = LastSourceHost, - TContext = SiemContext - > = Resolver; - export type SourceResolver< - R = Maybe, - Parent = LastSourceHost, - TContext = SiemContext - > = Resolver; - export type HostResolver< - R = Maybe, - Parent = LastSourceHost, - TContext = SiemContext - > = Resolver; -} - -export namespace SourceEcsFieldsResolvers { - export interface Resolvers { - bytes?: BytesResolver, TypeParent, TContext>; - - ip?: IpResolver, TypeParent, TContext>; - - port?: PortResolver, TypeParent, TContext>; - - domain?: DomainResolver, TypeParent, TContext>; - - geo?: GeoResolver, TypeParent, TContext>; - - packets?: PacketsResolver, TypeParent, TContext>; - } - - export type BytesResolver< - R = Maybe, - Parent = SourceEcsFields, - TContext = SiemContext - > = Resolver; - export type IpResolver< - R = Maybe, - Parent = SourceEcsFields, - TContext = SiemContext - > = Resolver; - export type PortResolver< - R = Maybe, - Parent = SourceEcsFields, - TContext = SiemContext - > = Resolver; - export type DomainResolver< - R = Maybe, - Parent = SourceEcsFields, - TContext = SiemContext - > = Resolver; - export type GeoResolver< - R = Maybe, - Parent = SourceEcsFields, - TContext = SiemContext - > = Resolver; - export type PacketsResolver< - R = Maybe, - Parent = SourceEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace GeoEcsFieldsResolvers { - export interface Resolvers { - city_name?: CityNameResolver, TypeParent, TContext>; - - continent_name?: ContinentNameResolver, TypeParent, TContext>; - - country_iso_code?: CountryIsoCodeResolver, TypeParent, TContext>; - - country_name?: CountryNameResolver, TypeParent, TContext>; - - location?: LocationResolver, TypeParent, TContext>; - - region_iso_code?: RegionIsoCodeResolver, TypeParent, TContext>; - - region_name?: RegionNameResolver, TypeParent, TContext>; - } - - export type CityNameResolver< - R = Maybe, - Parent = GeoEcsFields, - TContext = SiemContext - > = Resolver; - export type ContinentNameResolver< - R = Maybe, - Parent = GeoEcsFields, - TContext = SiemContext - > = Resolver; - export type CountryIsoCodeResolver< - R = Maybe, - Parent = GeoEcsFields, - TContext = SiemContext - > = Resolver; - export type CountryNameResolver< - R = Maybe, - Parent = GeoEcsFields, - TContext = SiemContext - > = Resolver; - export type LocationResolver< - R = Maybe, - Parent = GeoEcsFields, - TContext = SiemContext - > = Resolver; - export type RegionIsoCodeResolver< - R = Maybe, - Parent = GeoEcsFields, - TContext = SiemContext - > = Resolver; - export type RegionNameResolver< - R = Maybe, - Parent = GeoEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace LocationResolvers { - export interface Resolvers { - lon?: LonResolver, TypeParent, TContext>; - - lat?: LatResolver, TypeParent, TContext>; - } - - export type LonResolver< - R = Maybe, - Parent = Location, - TContext = SiemContext - > = Resolver; - export type LatResolver< - R = Maybe, - Parent = Location, - TContext = SiemContext - > = Resolver; -} - -export namespace HostEcsFieldsResolvers { - export interface Resolvers { - architecture?: ArchitectureResolver, TypeParent, TContext>; - - id?: IdResolver, TypeParent, TContext>; - - ip?: IpResolver, TypeParent, TContext>; - - mac?: MacResolver, TypeParent, TContext>; - - name?: NameResolver, TypeParent, TContext>; - - os?: OsResolver, TypeParent, TContext>; - - type?: TypeResolver, TypeParent, TContext>; - } - - export type ArchitectureResolver< - R = Maybe, - Parent = HostEcsFields, - TContext = SiemContext - > = Resolver; - export type IdResolver< - R = Maybe, - Parent = HostEcsFields, - TContext = SiemContext - > = Resolver; - export type IpResolver< - R = Maybe, - Parent = HostEcsFields, - TContext = SiemContext - > = Resolver; - export type MacResolver< - R = Maybe, - Parent = HostEcsFields, - TContext = SiemContext - > = Resolver; - export type NameResolver< - R = Maybe, - Parent = HostEcsFields, - TContext = SiemContext - > = Resolver; - export type OsResolver< - R = Maybe, - Parent = HostEcsFields, - TContext = SiemContext - > = Resolver; - export type TypeResolver< - R = Maybe, - Parent = HostEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace OsEcsFieldsResolvers { - export interface Resolvers { - platform?: PlatformResolver, TypeParent, TContext>; - - name?: NameResolver, TypeParent, TContext>; - - full?: FullResolver, TypeParent, TContext>; - - family?: FamilyResolver, TypeParent, TContext>; - - version?: VersionResolver, TypeParent, TContext>; - - kernel?: KernelResolver, TypeParent, TContext>; - } - - export type PlatformResolver< - R = Maybe, - Parent = OsEcsFields, - TContext = SiemContext - > = Resolver; - export type NameResolver< - R = Maybe, - Parent = OsEcsFields, - TContext = SiemContext - > = Resolver; - export type FullResolver< - R = Maybe, - Parent = OsEcsFields, - TContext = SiemContext - > = Resolver; - export type FamilyResolver< - R = Maybe, - Parent = OsEcsFields, - TContext = SiemContext - > = Resolver; - export type VersionResolver< - R = Maybe, - Parent = OsEcsFields, - TContext = SiemContext - > = Resolver; - export type KernelResolver< - R = Maybe, - Parent = OsEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace CursorTypeResolvers { - export interface Resolvers { - value?: ValueResolver, TypeParent, TContext>; - - tiebreaker?: TiebreakerResolver, TypeParent, TContext>; - } - - export type ValueResolver< - R = Maybe, - Parent = CursorType, - TContext = SiemContext - > = Resolver; - export type TiebreakerResolver< - R = Maybe, - Parent = CursorType, - TContext = SiemContext - > = Resolver; -} - -export namespace PageInfoPaginatedResolvers { - export interface Resolvers { - activePage?: ActivePageResolver; - - fakeTotalCount?: FakeTotalCountResolver; - - showMorePagesIndicator?: ShowMorePagesIndicatorResolver; - } - - export type ActivePageResolver< - R = number, - Parent = PageInfoPaginated, - TContext = SiemContext - > = Resolver; - export type FakeTotalCountResolver< - R = number, - Parent = PageInfoPaginated, - TContext = SiemContext - > = Resolver; - export type ShowMorePagesIndicatorResolver< - R = boolean, - Parent = PageInfoPaginated, - TContext = SiemContext - > = Resolver; -} - -export namespace InspectResolvers { - export interface Resolvers { - dsl?: DslResolver; - - response?: ResponseResolver; - } - - export type DslResolver = Resolver< - R, - Parent, - TContext - >; - export type ResponseResolver = Resolver< - R, - Parent, - TContext - >; -} - -export namespace TimelineDataResolvers { - export interface Resolvers { - edges?: EdgesResolver; - - totalCount?: TotalCountResolver; - - pageInfo?: PageInfoResolver; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type EdgesResolver< - R = TimelineEdges[], - Parent = TimelineData, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver< - R = number, - Parent = TimelineData, - TContext = SiemContext - > = Resolver; - export type PageInfoResolver< - R = PageInfo, - Parent = TimelineData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = TimelineData, - TContext = SiemContext - > = Resolver; -} - -export namespace TimelineEdgesResolvers { - export interface Resolvers { - node?: NodeResolver; - - cursor?: CursorResolver; - } - export type NodeResolver< - R = TimelineItem, - Parent = TimelineEdges, - TContext = SiemContext - > = Resolver; - export type CursorResolver< - R = CursorType, - Parent = TimelineEdges, - TContext = SiemContext - > = Resolver; +export interface SubscriptionResolverObject { + subscribe: SubscriptionSubscribeFn; + resolve: SubscriptionResolveFn; } -export namespace TimelineItemResolvers { - export interface Resolvers { - _id?: _IdResolver; +export type SubscriptionObject = + | SubscriptionSubscriberObject + | SubscriptionResolverObject; + +export type SubscriptionResolver = + | ((...args: any[]) => SubscriptionObject) + | SubscriptionObject; + +export type TypeResolveFn = ( + parent: TParent, + context: TContext, + info: GraphQLResolveInfo +) => Maybe; - _index?: _IndexResolver, TypeParent, TContext>; +export type isTypeOfResolverFn = (obj: T, info: GraphQLResolveInfo) => boolean; - data?: DataResolver; +export type NextResolverFn = () => Promise; - ecs?: EcsResolver; - } +export type DirectiveResolverFn = ( + next: NextResolverFn, + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => TResult | Promise; - export type _IdResolver = Resolver< - R, - Parent, - TContext - >; - export type _IndexResolver< - R = Maybe, - Parent = TimelineItem, - TContext = SiemContext - > = Resolver; - export type DataResolver< - R = TimelineNonEcsData[], - Parent = TimelineItem, - TContext = SiemContext - > = Resolver; - export type EcsResolver = Resolver< - R, - Parent, - TContext - >; -} - -export namespace TimelineNonEcsDataResolvers { - export interface Resolvers { - field?: FieldResolver; - - value?: ValueResolver, TypeParent, TContext>; - } - - export type FieldResolver< - R = string, - Parent = TimelineNonEcsData, - TContext = SiemContext - > = Resolver; - export type ValueResolver< - R = Maybe, - Parent = TimelineNonEcsData, - TContext = SiemContext - > = Resolver; -} - -export namespace EcsResolvers { - export interface Resolvers { - _id?: _IdResolver; - - _index?: _IndexResolver, TypeParent, TContext>; - - auditd?: AuditdResolver, TypeParent, TContext>; - - destination?: DestinationResolver, TypeParent, TContext>; - - dns?: DnsResolver, TypeParent, TContext>; - - endgame?: EndgameResolver, TypeParent, TContext>; - - event?: EventResolver, TypeParent, TContext>; - - geo?: GeoResolver, TypeParent, TContext>; - - host?: HostResolver, TypeParent, TContext>; - - network?: NetworkResolver, TypeParent, TContext>; - - rule?: RuleResolver, TypeParent, TContext>; - - signal?: SignalResolver, TypeParent, TContext>; - - source?: SourceResolver, TypeParent, TContext>; - - suricata?: SuricataResolver, TypeParent, TContext>; - - tls?: TlsResolver, TypeParent, TContext>; - - zeek?: ZeekResolver, TypeParent, TContext>; - - http?: HttpResolver, TypeParent, TContext>; - - url?: UrlResolver, TypeParent, TContext>; - - timestamp?: TimestampResolver, TypeParent, TContext>; - - message?: MessageResolver, TypeParent, TContext>; - - user?: UserResolver, TypeParent, TContext>; - - winlog?: WinlogResolver, TypeParent, TContext>; - - process?: ProcessResolver, TypeParent, TContext>; - - file?: FileResolver, TypeParent, TContext>; - - system?: SystemResolver, TypeParent, TContext>; - } - - export type _IdResolver = Resolver< - R, - Parent, - TContext - >; - export type _IndexResolver, Parent = Ecs, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type AuditdResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type DestinationResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type DnsResolver, Parent = Ecs, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type EndgameResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type EventResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type GeoResolver, Parent = Ecs, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type HostResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type NetworkResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type RuleResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type SignalResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type SourceResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type SuricataResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type TlsResolver, Parent = Ecs, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type ZeekResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type HttpResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type UrlResolver, Parent = Ecs, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type TimestampResolver, Parent = Ecs, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type MessageResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type UserResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type WinlogResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type ProcessResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; - export type FileResolver, Parent = Ecs, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type SystemResolver< - R = Maybe, - Parent = Ecs, - TContext = SiemContext - > = Resolver; -} - -export namespace AuditdEcsFieldsResolvers { - export interface Resolvers { - result?: ResultResolver, TypeParent, TContext>; - - session?: SessionResolver, TypeParent, TContext>; - - data?: DataResolver, TypeParent, TContext>; - - summary?: SummaryResolver, TypeParent, TContext>; - - sequence?: SequenceResolver, TypeParent, TContext>; - } - - export type ResultResolver< - R = Maybe, - Parent = AuditdEcsFields, - TContext = SiemContext - > = Resolver; - export type SessionResolver< - R = Maybe, - Parent = AuditdEcsFields, - TContext = SiemContext - > = Resolver; - export type DataResolver< - R = Maybe, - Parent = AuditdEcsFields, - TContext = SiemContext - > = Resolver; - export type SummaryResolver< - R = Maybe, - Parent = AuditdEcsFields, - TContext = SiemContext - > = Resolver; - export type SequenceResolver< - R = Maybe, - Parent = AuditdEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace AuditdDataResolvers { - export interface Resolvers { - acct?: AcctResolver, TypeParent, TContext>; - - terminal?: TerminalResolver, TypeParent, TContext>; - - op?: OpResolver, TypeParent, TContext>; - } - - export type AcctResolver< - R = Maybe, - Parent = AuditdData, - TContext = SiemContext - > = Resolver; - export type TerminalResolver< - R = Maybe, - Parent = AuditdData, - TContext = SiemContext - > = Resolver; - export type OpResolver< - R = Maybe, - Parent = AuditdData, - TContext = SiemContext - > = Resolver; -} - -export namespace SummaryResolvers { - export interface Resolvers { - actor?: ActorResolver, TypeParent, TContext>; - - object?: ObjectResolver, TypeParent, TContext>; - - how?: HowResolver, TypeParent, TContext>; - - message_type?: MessageTypeResolver, TypeParent, TContext>; - - sequence?: SequenceResolver, TypeParent, TContext>; - } - - export type ActorResolver< - R = Maybe, - Parent = Summary, - TContext = SiemContext - > = Resolver; - export type ObjectResolver< - R = Maybe, - Parent = Summary, - TContext = SiemContext - > = Resolver; - export type HowResolver< - R = Maybe, - Parent = Summary, - TContext = SiemContext - > = Resolver; - export type MessageTypeResolver< - R = Maybe, - Parent = Summary, - TContext = SiemContext - > = Resolver; - export type SequenceResolver< - R = Maybe, - Parent = Summary, - TContext = SiemContext - > = Resolver; -} - -export namespace PrimarySecondaryResolvers { - export interface Resolvers { - primary?: PrimaryResolver, TypeParent, TContext>; - - secondary?: SecondaryResolver, TypeParent, TContext>; - - type?: TypeResolver, TypeParent, TContext>; - } - - export type PrimaryResolver< - R = Maybe, - Parent = PrimarySecondary, - TContext = SiemContext - > = Resolver; - export type SecondaryResolver< - R = Maybe, - Parent = PrimarySecondary, - TContext = SiemContext - > = Resolver; - export type TypeResolver< - R = Maybe, - Parent = PrimarySecondary, - TContext = SiemContext - > = Resolver; -} - -export namespace DestinationEcsFieldsResolvers { - export interface Resolvers { - bytes?: BytesResolver, TypeParent, TContext>; - - ip?: IpResolver, TypeParent, TContext>; - - port?: PortResolver, TypeParent, TContext>; - - domain?: DomainResolver, TypeParent, TContext>; - - geo?: GeoResolver, TypeParent, TContext>; - - packets?: PacketsResolver, TypeParent, TContext>; - } - - export type BytesResolver< - R = Maybe, - Parent = DestinationEcsFields, - TContext = SiemContext - > = Resolver; - export type IpResolver< - R = Maybe, - Parent = DestinationEcsFields, - TContext = SiemContext - > = Resolver; - export type PortResolver< - R = Maybe, - Parent = DestinationEcsFields, - TContext = SiemContext - > = Resolver; - export type DomainResolver< - R = Maybe, - Parent = DestinationEcsFields, - TContext = SiemContext - > = Resolver; - export type GeoResolver< - R = Maybe, - Parent = DestinationEcsFields, - TContext = SiemContext - > = Resolver; - export type PacketsResolver< - R = Maybe, - Parent = DestinationEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace DnsEcsFieldsResolvers { - export interface Resolvers { - question?: QuestionResolver, TypeParent, TContext>; - - resolved_ip?: ResolvedIpResolver, TypeParent, TContext>; - - response_code?: ResponseCodeResolver, TypeParent, TContext>; - } - - export type QuestionResolver< - R = Maybe, - Parent = DnsEcsFields, - TContext = SiemContext - > = Resolver; - export type ResolvedIpResolver< - R = Maybe, - Parent = DnsEcsFields, - TContext = SiemContext - > = Resolver; - export type ResponseCodeResolver< - R = Maybe, - Parent = DnsEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace DnsQuestionDataResolvers { - export interface Resolvers { - name?: NameResolver, TypeParent, TContext>; - - type?: TypeResolver, TypeParent, TContext>; - } - - export type NameResolver< - R = Maybe, - Parent = DnsQuestionData, - TContext = SiemContext - > = Resolver; - export type TypeResolver< - R = Maybe, - Parent = DnsQuestionData, - TContext = SiemContext - > = Resolver; -} - -export namespace EndgameEcsFieldsResolvers { - export interface Resolvers { - exit_code?: ExitCodeResolver, TypeParent, TContext>; - - file_name?: FileNameResolver, TypeParent, TContext>; - - file_path?: FilePathResolver, TypeParent, TContext>; - - logon_type?: LogonTypeResolver, TypeParent, TContext>; - - parent_process_name?: ParentProcessNameResolver, TypeParent, TContext>; - - pid?: PidResolver, TypeParent, TContext>; - - process_name?: ProcessNameResolver, TypeParent, TContext>; - - subject_domain_name?: SubjectDomainNameResolver, TypeParent, TContext>; - - subject_logon_id?: SubjectLogonIdResolver, TypeParent, TContext>; - - subject_user_name?: SubjectUserNameResolver, TypeParent, TContext>; - - target_domain_name?: TargetDomainNameResolver, TypeParent, TContext>; - - target_logon_id?: TargetLogonIdResolver, TypeParent, TContext>; - - target_user_name?: TargetUserNameResolver, TypeParent, TContext>; - } - - export type ExitCodeResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; - export type FileNameResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; - export type FilePathResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; - export type LogonTypeResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; - export type ParentProcessNameResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; - export type PidResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; - export type ProcessNameResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; - export type SubjectDomainNameResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; - export type SubjectLogonIdResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; - export type SubjectUserNameResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; - export type TargetDomainNameResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; - export type TargetLogonIdResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; - export type TargetUserNameResolver< - R = Maybe, - Parent = EndgameEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace EventEcsFieldsResolvers { - export interface Resolvers { - action?: ActionResolver, TypeParent, TContext>; - - category?: CategoryResolver, TypeParent, TContext>; - - code?: CodeResolver, TypeParent, TContext>; - - created?: CreatedResolver, TypeParent, TContext>; - - dataset?: DatasetResolver, TypeParent, TContext>; - - duration?: DurationResolver, TypeParent, TContext>; - - end?: EndResolver, TypeParent, TContext>; - - hash?: HashResolver, TypeParent, TContext>; - - id?: IdResolver, TypeParent, TContext>; - - kind?: KindResolver, TypeParent, TContext>; - - module?: ModuleResolver, TypeParent, TContext>; - - original?: OriginalResolver, TypeParent, TContext>; - - outcome?: OutcomeResolver, TypeParent, TContext>; - - risk_score?: RiskScoreResolver, TypeParent, TContext>; - - risk_score_norm?: RiskScoreNormResolver, TypeParent, TContext>; - - severity?: SeverityResolver, TypeParent, TContext>; - - start?: StartResolver, TypeParent, TContext>; - - timezone?: TimezoneResolver, TypeParent, TContext>; - - type?: TypeResolver, TypeParent, TContext>; - } - - export type ActionResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type CategoryResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type CodeResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type CreatedResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type DatasetResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type DurationResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type EndResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type HashResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type IdResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type KindResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type ModuleResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type OriginalResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type OutcomeResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type RiskScoreResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type RiskScoreNormResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type SeverityResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type StartResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type TimezoneResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; - export type TypeResolver< - R = Maybe, - Parent = EventEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkEcsFieldResolvers { - export interface Resolvers { - bytes?: BytesResolver, TypeParent, TContext>; - - community_id?: CommunityIdResolver, TypeParent, TContext>; - - direction?: DirectionResolver, TypeParent, TContext>; - - packets?: PacketsResolver, TypeParent, TContext>; - - protocol?: ProtocolResolver, TypeParent, TContext>; - - transport?: TransportResolver, TypeParent, TContext>; - } - - export type BytesResolver< - R = Maybe, - Parent = NetworkEcsField, - TContext = SiemContext - > = Resolver; - export type CommunityIdResolver< - R = Maybe, - Parent = NetworkEcsField, - TContext = SiemContext - > = Resolver; - export type DirectionResolver< - R = Maybe, - Parent = NetworkEcsField, - TContext = SiemContext - > = Resolver; - export type PacketsResolver< - R = Maybe, - Parent = NetworkEcsField, - TContext = SiemContext - > = Resolver; - export type ProtocolResolver< - R = Maybe, - Parent = NetworkEcsField, - TContext = SiemContext - > = Resolver; - export type TransportResolver< - R = Maybe, - Parent = NetworkEcsField, - TContext = SiemContext - > = Resolver; -} - -export namespace RuleEcsFieldResolvers { - export interface Resolvers { - reference?: ReferenceResolver, TypeParent, TContext>; - } - - export type ReferenceResolver< - R = Maybe, - Parent = RuleEcsField, - TContext = SiemContext - > = Resolver; -} - -export namespace SignalFieldResolvers { - export interface Resolvers { - rule?: RuleResolver, TypeParent, TContext>; - - original_time?: OriginalTimeResolver, TypeParent, TContext>; - } - - export type RuleResolver< - R = Maybe, - Parent = SignalField, - TContext = SiemContext - > = Resolver; - export type OriginalTimeResolver< - R = Maybe, - Parent = SignalField, - TContext = SiemContext - > = Resolver; -} - -export namespace RuleFieldResolvers { - export interface Resolvers { - id?: IdResolver, TypeParent, TContext>; - - rule_id?: RuleIdResolver, TypeParent, TContext>; - - false_positives?: FalsePositivesResolver; - - saved_id?: SavedIdResolver, TypeParent, TContext>; - - timeline_id?: TimelineIdResolver, TypeParent, TContext>; - - timeline_title?: TimelineTitleResolver, TypeParent, TContext>; - - max_signals?: MaxSignalsResolver, TypeParent, TContext>; - - risk_score?: RiskScoreResolver, TypeParent, TContext>; - - output_index?: OutputIndexResolver, TypeParent, TContext>; - - description?: DescriptionResolver, TypeParent, TContext>; - - from?: FromResolver, TypeParent, TContext>; - - immutable?: ImmutableResolver, TypeParent, TContext>; - - index?: IndexResolver, TypeParent, TContext>; - - interval?: IntervalResolver, TypeParent, TContext>; - - language?: LanguageResolver, TypeParent, TContext>; - - query?: QueryResolver, TypeParent, TContext>; - - references?: ReferencesResolver, TypeParent, TContext>; - - severity?: SeverityResolver, TypeParent, TContext>; - - tags?: TagsResolver, TypeParent, TContext>; - - threat?: ThreatResolver, TypeParent, TContext>; - - type?: TypeResolver, TypeParent, TContext>; - - size?: SizeResolver, TypeParent, TContext>; - - to?: ToResolver, TypeParent, TContext>; - - enabled?: EnabledResolver, TypeParent, TContext>; - - filters?: FiltersResolver, TypeParent, TContext>; - - created_at?: CreatedAtResolver, TypeParent, TContext>; - - updated_at?: UpdatedAtResolver, TypeParent, TContext>; - - created_by?: CreatedByResolver, TypeParent, TContext>; - - updated_by?: UpdatedByResolver, TypeParent, TContext>; - - version?: VersionResolver, TypeParent, TContext>; - } - - export type IdResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type RuleIdResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type FalsePositivesResolver< - R = string[], - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type SavedIdResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type TimelineIdResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type TimelineTitleResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type MaxSignalsResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type RiskScoreResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type OutputIndexResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type DescriptionResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type FromResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type ImmutableResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type IndexResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type IntervalResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type LanguageResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type QueryResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type ReferencesResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type SeverityResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type TagsResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type ThreatResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type TypeResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type SizeResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type ToResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type EnabledResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type FiltersResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type CreatedAtResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type UpdatedAtResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type CreatedByResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type UpdatedByResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; - export type VersionResolver< - R = Maybe, - Parent = RuleField, - TContext = SiemContext - > = Resolver; -} - -export namespace SuricataEcsFieldsResolvers { - export interface Resolvers { - eve?: EveResolver, TypeParent, TContext>; - } - - export type EveResolver< - R = Maybe, - Parent = SuricataEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace SuricataEveDataResolvers { - export interface Resolvers { - alert?: AlertResolver, TypeParent, TContext>; - - flow_id?: FlowIdResolver, TypeParent, TContext>; - - proto?: ProtoResolver, TypeParent, TContext>; - } - - export type AlertResolver< - R = Maybe, - Parent = SuricataEveData, - TContext = SiemContext - > = Resolver; - export type FlowIdResolver< - R = Maybe, - Parent = SuricataEveData, - TContext = SiemContext - > = Resolver; - export type ProtoResolver< - R = Maybe, - Parent = SuricataEveData, - TContext = SiemContext - > = Resolver; -} - -export namespace SuricataAlertDataResolvers { - export interface Resolvers { - signature?: SignatureResolver, TypeParent, TContext>; - - signature_id?: SignatureIdResolver, TypeParent, TContext>; - } - - export type SignatureResolver< - R = Maybe, - Parent = SuricataAlertData, - TContext = SiemContext - > = Resolver; - export type SignatureIdResolver< - R = Maybe, - Parent = SuricataAlertData, - TContext = SiemContext - > = Resolver; -} - -export namespace TlsEcsFieldsResolvers { - export interface Resolvers { - client_certificate?: ClientCertificateResolver< - Maybe, - TypeParent, - TContext - >; - - fingerprints?: FingerprintsResolver, TypeParent, TContext>; - - server_certificate?: ServerCertificateResolver< - Maybe, - TypeParent, - TContext - >; - } - - export type ClientCertificateResolver< - R = Maybe, - Parent = TlsEcsFields, - TContext = SiemContext - > = Resolver; - export type FingerprintsResolver< - R = Maybe, - Parent = TlsEcsFields, - TContext = SiemContext - > = Resolver; - export type ServerCertificateResolver< - R = Maybe, - Parent = TlsEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace TlsClientCertificateDataResolvers { - export interface Resolvers { - fingerprint?: FingerprintResolver, TypeParent, TContext>; - } - - export type FingerprintResolver< - R = Maybe, - Parent = TlsClientCertificateData, - TContext = SiemContext - > = Resolver; -} - -export namespace FingerprintDataResolvers { - export interface Resolvers { - sha1?: Sha1Resolver, TypeParent, TContext>; - } - - export type Sha1Resolver< - R = Maybe, - Parent = FingerprintData, - TContext = SiemContext - > = Resolver; -} - -export namespace TlsFingerprintsDataResolvers { - export interface Resolvers { - ja3?: Ja3Resolver, TypeParent, TContext>; - } - - export type Ja3Resolver< - R = Maybe, - Parent = TlsFingerprintsData, - TContext = SiemContext - > = Resolver; -} - -export namespace TlsJa3DataResolvers { - export interface Resolvers { - hash?: HashResolver, TypeParent, TContext>; - } - - export type HashResolver< - R = Maybe, - Parent = TlsJa3Data, - TContext = SiemContext - > = Resolver; -} - -export namespace TlsServerCertificateDataResolvers { - export interface Resolvers { - fingerprint?: FingerprintResolver, TypeParent, TContext>; - } - - export type FingerprintResolver< - R = Maybe, - Parent = TlsServerCertificateData, - TContext = SiemContext - > = Resolver; -} - -export namespace ZeekEcsFieldsResolvers { - export interface Resolvers { - session_id?: SessionIdResolver, TypeParent, TContext>; - - connection?: ConnectionResolver, TypeParent, TContext>; - - notice?: NoticeResolver, TypeParent, TContext>; - - dns?: DnsResolver, TypeParent, TContext>; - - http?: HttpResolver, TypeParent, TContext>; - - files?: FilesResolver, TypeParent, TContext>; - - ssl?: SslResolver, TypeParent, TContext>; - } - - export type SessionIdResolver< - R = Maybe, - Parent = ZeekEcsFields, - TContext = SiemContext - > = Resolver; - export type ConnectionResolver< - R = Maybe, - Parent = ZeekEcsFields, - TContext = SiemContext - > = Resolver; - export type NoticeResolver< - R = Maybe, - Parent = ZeekEcsFields, - TContext = SiemContext - > = Resolver; - export type DnsResolver< - R = Maybe, - Parent = ZeekEcsFields, - TContext = SiemContext - > = Resolver; - export type HttpResolver< - R = Maybe, - Parent = ZeekEcsFields, - TContext = SiemContext - > = Resolver; - export type FilesResolver< - R = Maybe, - Parent = ZeekEcsFields, - TContext = SiemContext - > = Resolver; - export type SslResolver< - R = Maybe, - Parent = ZeekEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace ZeekConnectionDataResolvers { - export interface Resolvers { - local_resp?: LocalRespResolver, TypeParent, TContext>; - - local_orig?: LocalOrigResolver, TypeParent, TContext>; - - missed_bytes?: MissedBytesResolver, TypeParent, TContext>; - - state?: StateResolver, TypeParent, TContext>; - - history?: HistoryResolver, TypeParent, TContext>; - } - - export type LocalRespResolver< - R = Maybe, - Parent = ZeekConnectionData, - TContext = SiemContext - > = Resolver; - export type LocalOrigResolver< - R = Maybe, - Parent = ZeekConnectionData, - TContext = SiemContext - > = Resolver; - export type MissedBytesResolver< - R = Maybe, - Parent = ZeekConnectionData, - TContext = SiemContext - > = Resolver; - export type StateResolver< - R = Maybe, - Parent = ZeekConnectionData, - TContext = SiemContext - > = Resolver; - export type HistoryResolver< - R = Maybe, - Parent = ZeekConnectionData, - TContext = SiemContext - > = Resolver; -} - -export namespace ZeekNoticeDataResolvers { - export interface Resolvers { - suppress_for?: SuppressForResolver, TypeParent, TContext>; - - msg?: MsgResolver, TypeParent, TContext>; - - note?: NoteResolver, TypeParent, TContext>; - - sub?: SubResolver, TypeParent, TContext>; - - dst?: DstResolver, TypeParent, TContext>; - - dropped?: DroppedResolver, TypeParent, TContext>; - - peer_descr?: PeerDescrResolver, TypeParent, TContext>; - } - - export type SuppressForResolver< - R = Maybe, - Parent = ZeekNoticeData, - TContext = SiemContext - > = Resolver; - export type MsgResolver< - R = Maybe, - Parent = ZeekNoticeData, - TContext = SiemContext - > = Resolver; - export type NoteResolver< - R = Maybe, - Parent = ZeekNoticeData, - TContext = SiemContext - > = Resolver; - export type SubResolver< - R = Maybe, - Parent = ZeekNoticeData, - TContext = SiemContext - > = Resolver; - export type DstResolver< - R = Maybe, - Parent = ZeekNoticeData, - TContext = SiemContext - > = Resolver; - export type DroppedResolver< - R = Maybe, - Parent = ZeekNoticeData, - TContext = SiemContext - > = Resolver; - export type PeerDescrResolver< - R = Maybe, - Parent = ZeekNoticeData, - TContext = SiemContext - > = Resolver; -} - -export namespace ZeekDnsDataResolvers { - export interface Resolvers { - AA?: AaResolver, TypeParent, TContext>; - - qclass_name?: QclassNameResolver, TypeParent, TContext>; - - RD?: RdResolver, TypeParent, TContext>; - - qtype_name?: QtypeNameResolver, TypeParent, TContext>; - - rejected?: RejectedResolver, TypeParent, TContext>; - - qtype?: QtypeResolver, TypeParent, TContext>; - - query?: QueryResolver, TypeParent, TContext>; - - trans_id?: TransIdResolver, TypeParent, TContext>; - - qclass?: QclassResolver, TypeParent, TContext>; - - RA?: RaResolver, TypeParent, TContext>; - - TC?: TcResolver, TypeParent, TContext>; - } - - export type AaResolver< - R = Maybe, - Parent = ZeekDnsData, - TContext = SiemContext - > = Resolver; - export type QclassNameResolver< - R = Maybe, - Parent = ZeekDnsData, - TContext = SiemContext - > = Resolver; - export type RdResolver< - R = Maybe, - Parent = ZeekDnsData, - TContext = SiemContext - > = Resolver; - export type QtypeNameResolver< - R = Maybe, - Parent = ZeekDnsData, - TContext = SiemContext - > = Resolver; - export type RejectedResolver< - R = Maybe, - Parent = ZeekDnsData, - TContext = SiemContext - > = Resolver; - export type QtypeResolver< - R = Maybe, - Parent = ZeekDnsData, - TContext = SiemContext - > = Resolver; - export type QueryResolver< - R = Maybe, - Parent = ZeekDnsData, - TContext = SiemContext - > = Resolver; - export type TransIdResolver< - R = Maybe, - Parent = ZeekDnsData, - TContext = SiemContext - > = Resolver; - export type QclassResolver< - R = Maybe, - Parent = ZeekDnsData, - TContext = SiemContext - > = Resolver; - export type RaResolver< - R = Maybe, - Parent = ZeekDnsData, - TContext = SiemContext - > = Resolver; - export type TcResolver< - R = Maybe, - Parent = ZeekDnsData, - TContext = SiemContext - > = Resolver; -} - -export namespace ZeekHttpDataResolvers { - export interface Resolvers { - resp_mime_types?: RespMimeTypesResolver, TypeParent, TContext>; - - trans_depth?: TransDepthResolver, TypeParent, TContext>; - - status_msg?: StatusMsgResolver, TypeParent, TContext>; - - resp_fuids?: RespFuidsResolver, TypeParent, TContext>; - - tags?: TagsResolver, TypeParent, TContext>; - } - - export type RespMimeTypesResolver< - R = Maybe, - Parent = ZeekHttpData, - TContext = SiemContext - > = Resolver; - export type TransDepthResolver< - R = Maybe, - Parent = ZeekHttpData, - TContext = SiemContext - > = Resolver; - export type StatusMsgResolver< - R = Maybe, - Parent = ZeekHttpData, - TContext = SiemContext - > = Resolver; - export type RespFuidsResolver< - R = Maybe, - Parent = ZeekHttpData, - TContext = SiemContext - > = Resolver; - export type TagsResolver< - R = Maybe, - Parent = ZeekHttpData, - TContext = SiemContext - > = Resolver; -} - -export namespace ZeekFileDataResolvers { - export interface Resolvers { - session_ids?: SessionIdsResolver, TypeParent, TContext>; - - timedout?: TimedoutResolver, TypeParent, TContext>; - - local_orig?: LocalOrigResolver, TypeParent, TContext>; - - tx_host?: TxHostResolver, TypeParent, TContext>; - - source?: SourceResolver, TypeParent, TContext>; - - is_orig?: IsOrigResolver, TypeParent, TContext>; - - overflow_bytes?: OverflowBytesResolver, TypeParent, TContext>; - - sha1?: Sha1Resolver, TypeParent, TContext>; - - duration?: DurationResolver, TypeParent, TContext>; - - depth?: DepthResolver, TypeParent, TContext>; - - analyzers?: AnalyzersResolver, TypeParent, TContext>; - - mime_type?: MimeTypeResolver, TypeParent, TContext>; - - rx_host?: RxHostResolver, TypeParent, TContext>; - - total_bytes?: TotalBytesResolver, TypeParent, TContext>; - - fuid?: FuidResolver, TypeParent, TContext>; - - seen_bytes?: SeenBytesResolver, TypeParent, TContext>; - - missing_bytes?: MissingBytesResolver, TypeParent, TContext>; - - md5?: Md5Resolver, TypeParent, TContext>; - } - - export type SessionIdsResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type TimedoutResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type LocalOrigResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type TxHostResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type SourceResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type IsOrigResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type OverflowBytesResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type Sha1Resolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type DurationResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type DepthResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type AnalyzersResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type MimeTypeResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type RxHostResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type TotalBytesResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type FuidResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type SeenBytesResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type MissingBytesResolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; - export type Md5Resolver< - R = Maybe, - Parent = ZeekFileData, - TContext = SiemContext - > = Resolver; -} - -export namespace ZeekSslDataResolvers { - export interface Resolvers { - cipher?: CipherResolver, TypeParent, TContext>; - - established?: EstablishedResolver, TypeParent, TContext>; - - resumed?: ResumedResolver, TypeParent, TContext>; - - version?: VersionResolver, TypeParent, TContext>; - } - - export type CipherResolver< - R = Maybe, - Parent = ZeekSslData, - TContext = SiemContext - > = Resolver; - export type EstablishedResolver< - R = Maybe, - Parent = ZeekSslData, - TContext = SiemContext - > = Resolver; - export type ResumedResolver< - R = Maybe, - Parent = ZeekSslData, - TContext = SiemContext - > = Resolver; - export type VersionResolver< - R = Maybe, - Parent = ZeekSslData, - TContext = SiemContext - > = Resolver; -} - -export namespace HttpEcsFieldsResolvers { - export interface Resolvers { - version?: VersionResolver, TypeParent, TContext>; - - request?: RequestResolver, TypeParent, TContext>; - - response?: ResponseResolver, TypeParent, TContext>; - } - - export type VersionResolver< - R = Maybe, - Parent = HttpEcsFields, - TContext = SiemContext - > = Resolver; - export type RequestResolver< - R = Maybe, - Parent = HttpEcsFields, - TContext = SiemContext - > = Resolver; - export type ResponseResolver< - R = Maybe, - Parent = HttpEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace HttpRequestDataResolvers { - export interface Resolvers { - method?: MethodResolver, TypeParent, TContext>; - - body?: BodyResolver, TypeParent, TContext>; - - referrer?: ReferrerResolver, TypeParent, TContext>; - - bytes?: BytesResolver, TypeParent, TContext>; - } - - export type MethodResolver< - R = Maybe, - Parent = HttpRequestData, - TContext = SiemContext - > = Resolver; - export type BodyResolver< - R = Maybe, - Parent = HttpRequestData, - TContext = SiemContext - > = Resolver; - export type ReferrerResolver< - R = Maybe, - Parent = HttpRequestData, - TContext = SiemContext - > = Resolver; - export type BytesResolver< - R = Maybe, - Parent = HttpRequestData, - TContext = SiemContext - > = Resolver; -} - -export namespace HttpBodyDataResolvers { - export interface Resolvers { - content?: ContentResolver, TypeParent, TContext>; - - bytes?: BytesResolver, TypeParent, TContext>; - } - - export type ContentResolver< - R = Maybe, - Parent = HttpBodyData, - TContext = SiemContext - > = Resolver; - export type BytesResolver< - R = Maybe, - Parent = HttpBodyData, - TContext = SiemContext - > = Resolver; -} - -export namespace HttpResponseDataResolvers { - export interface Resolvers { - status_code?: StatusCodeResolver, TypeParent, TContext>; - - body?: BodyResolver, TypeParent, TContext>; - - bytes?: BytesResolver, TypeParent, TContext>; - } - - export type StatusCodeResolver< - R = Maybe, - Parent = HttpResponseData, - TContext = SiemContext - > = Resolver; - export type BodyResolver< - R = Maybe, - Parent = HttpResponseData, - TContext = SiemContext - > = Resolver; - export type BytesResolver< - R = Maybe, - Parent = HttpResponseData, - TContext = SiemContext - > = Resolver; -} - -export namespace UrlEcsFieldsResolvers { - export interface Resolvers { - domain?: DomainResolver, TypeParent, TContext>; - - original?: OriginalResolver, TypeParent, TContext>; - - username?: UsernameResolver, TypeParent, TContext>; - - password?: PasswordResolver, TypeParent, TContext>; - } - - export type DomainResolver< - R = Maybe, - Parent = UrlEcsFields, - TContext = SiemContext - > = Resolver; - export type OriginalResolver< - R = Maybe, - Parent = UrlEcsFields, - TContext = SiemContext - > = Resolver; - export type UsernameResolver< - R = Maybe, - Parent = UrlEcsFields, - TContext = SiemContext - > = Resolver; - export type PasswordResolver< - R = Maybe, - Parent = UrlEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace WinlogEcsFieldsResolvers { - export interface Resolvers { - event_id?: EventIdResolver, TypeParent, TContext>; - } - - export type EventIdResolver< - R = Maybe, - Parent = WinlogEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace ProcessEcsFieldsResolvers { - export interface Resolvers { - hash?: HashResolver, TypeParent, TContext>; - - pid?: PidResolver, TypeParent, TContext>; - - name?: NameResolver, TypeParent, TContext>; - - ppid?: PpidResolver, TypeParent, TContext>; - - args?: ArgsResolver, TypeParent, TContext>; - - executable?: ExecutableResolver, TypeParent, TContext>; - - title?: TitleResolver, TypeParent, TContext>; - - thread?: ThreadResolver, TypeParent, TContext>; - - working_directory?: WorkingDirectoryResolver, TypeParent, TContext>; - } - - export type HashResolver< - R = Maybe, - Parent = ProcessEcsFields, - TContext = SiemContext - > = Resolver; - export type PidResolver< - R = Maybe, - Parent = ProcessEcsFields, - TContext = SiemContext - > = Resolver; - export type NameResolver< - R = Maybe, - Parent = ProcessEcsFields, - TContext = SiemContext - > = Resolver; - export type PpidResolver< - R = Maybe, - Parent = ProcessEcsFields, - TContext = SiemContext - > = Resolver; - export type ArgsResolver< - R = Maybe, - Parent = ProcessEcsFields, - TContext = SiemContext - > = Resolver; - export type ExecutableResolver< - R = Maybe, - Parent = ProcessEcsFields, - TContext = SiemContext - > = Resolver; - export type TitleResolver< - R = Maybe, - Parent = ProcessEcsFields, - TContext = SiemContext - > = Resolver; - export type ThreadResolver< - R = Maybe, - Parent = ProcessEcsFields, - TContext = SiemContext - > = Resolver; - export type WorkingDirectoryResolver< - R = Maybe, - Parent = ProcessEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace ProcessHashDataResolvers { - export interface Resolvers { - md5?: Md5Resolver, TypeParent, TContext>; - - sha1?: Sha1Resolver, TypeParent, TContext>; - - sha256?: Sha256Resolver, TypeParent, TContext>; - } - - export type Md5Resolver< - R = Maybe, - Parent = ProcessHashData, - TContext = SiemContext - > = Resolver; - export type Sha1Resolver< - R = Maybe, - Parent = ProcessHashData, - TContext = SiemContext - > = Resolver; - export type Sha256Resolver< - R = Maybe, - Parent = ProcessHashData, - TContext = SiemContext - > = Resolver; -} - -export namespace ThreadResolvers { - export interface Resolvers { - id?: IdResolver, TypeParent, TContext>; - - start?: StartResolver, TypeParent, TContext>; - } - - export type IdResolver< - R = Maybe, - Parent = Thread, - TContext = SiemContext - > = Resolver; - export type StartResolver< - R = Maybe, - Parent = Thread, - TContext = SiemContext - > = Resolver; -} - -export namespace FileFieldsResolvers { - export interface Resolvers { - name?: NameResolver, TypeParent, TContext>; - - path?: PathResolver, TypeParent, TContext>; - - target_path?: TargetPathResolver, TypeParent, TContext>; - - extension?: ExtensionResolver, TypeParent, TContext>; - - type?: TypeResolver, TypeParent, TContext>; - - device?: DeviceResolver, TypeParent, TContext>; - - inode?: InodeResolver, TypeParent, TContext>; - - uid?: UidResolver, TypeParent, TContext>; - - owner?: OwnerResolver, TypeParent, TContext>; - - gid?: GidResolver, TypeParent, TContext>; - - group?: GroupResolver, TypeParent, TContext>; - - mode?: ModeResolver, TypeParent, TContext>; - - size?: SizeResolver, TypeParent, TContext>; - - mtime?: MtimeResolver, TypeParent, TContext>; - - ctime?: CtimeResolver, TypeParent, TContext>; - } - - export type NameResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type PathResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type TargetPathResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type ExtensionResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type TypeResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type DeviceResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type InodeResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type UidResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type OwnerResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type GidResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type GroupResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type ModeResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type SizeResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type MtimeResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; - export type CtimeResolver< - R = Maybe, - Parent = FileFields, - TContext = SiemContext - > = Resolver; -} - -export namespace SystemEcsFieldResolvers { - export interface Resolvers { - audit?: AuditResolver, TypeParent, TContext>; - - auth?: AuthResolver, TypeParent, TContext>; - } - - export type AuditResolver< - R = Maybe, - Parent = SystemEcsField, - TContext = SiemContext - > = Resolver; - export type AuthResolver< - R = Maybe, - Parent = SystemEcsField, - TContext = SiemContext - > = Resolver; -} - -export namespace AuditEcsFieldsResolvers { - export interface Resolvers { - package?: PackageResolver, TypeParent, TContext>; - } - - export type PackageResolver< - R = Maybe, - Parent = AuditEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace PackageEcsFieldsResolvers { - export interface Resolvers { - arch?: ArchResolver, TypeParent, TContext>; - - entity_id?: EntityIdResolver, TypeParent, TContext>; - - name?: NameResolver, TypeParent, TContext>; - - size?: SizeResolver, TypeParent, TContext>; - - summary?: SummaryResolver, TypeParent, TContext>; - - version?: VersionResolver, TypeParent, TContext>; - } - - export type ArchResolver< - R = Maybe, - Parent = PackageEcsFields, - TContext = SiemContext - > = Resolver; - export type EntityIdResolver< - R = Maybe, - Parent = PackageEcsFields, - TContext = SiemContext - > = Resolver; - export type NameResolver< - R = Maybe, - Parent = PackageEcsFields, - TContext = SiemContext - > = Resolver; - export type SizeResolver< - R = Maybe, - Parent = PackageEcsFields, - TContext = SiemContext - > = Resolver; - export type SummaryResolver< - R = Maybe, - Parent = PackageEcsFields, - TContext = SiemContext - > = Resolver; - export type VersionResolver< - R = Maybe, - Parent = PackageEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace AuthEcsFieldsResolvers { - export interface Resolvers { - ssh?: SshResolver, TypeParent, TContext>; - } - - export type SshResolver< - R = Maybe, - Parent = AuthEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace SshEcsFieldsResolvers { - export interface Resolvers { - method?: MethodResolver, TypeParent, TContext>; - - signature?: SignatureResolver, TypeParent, TContext>; - } - - export type MethodResolver< - R = Maybe, - Parent = SshEcsFields, - TContext = SiemContext - > = Resolver; - export type SignatureResolver< - R = Maybe, - Parent = SshEcsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace PageInfoResolvers { - export interface Resolvers { - endCursor?: EndCursorResolver, TypeParent, TContext>; - - hasNextPage?: HasNextPageResolver, TypeParent, TContext>; - } - - export type EndCursorResolver< - R = Maybe, - Parent = PageInfo, - TContext = SiemContext - > = Resolver; - export type HasNextPageResolver< - R = Maybe, - Parent = PageInfo, - TContext = SiemContext - > = Resolver; -} - -export namespace TimelineDetailsDataResolvers { - export interface Resolvers { - data?: DataResolver, TypeParent, TContext>; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type DataResolver< - R = Maybe, - Parent = TimelineDetailsData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = TimelineDetailsData, - TContext = SiemContext - > = Resolver; -} - -export namespace DetailItemResolvers { - export interface Resolvers { - field?: FieldResolver; - - values?: ValuesResolver, TypeParent, TContext>; - - originalValue?: OriginalValueResolver, TypeParent, TContext>; - } - - export type FieldResolver = Resolver< - R, - Parent, - TContext - >; - export type ValuesResolver< - R = Maybe, - Parent = DetailItem, - TContext = SiemContext - > = Resolver; - export type OriginalValueResolver< - R = Maybe, - Parent = DetailItem, - TContext = SiemContext - > = Resolver; -} - -export namespace LastEventTimeDataResolvers { - export interface Resolvers { - lastSeen?: LastSeenResolver, TypeParent, TContext>; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type LastSeenResolver< - R = Maybe, - Parent = LastEventTimeData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = LastEventTimeData, - TContext = SiemContext - > = Resolver; -} - -export namespace HostsDataResolvers { - export interface Resolvers { - edges?: EdgesResolver; - - totalCount?: TotalCountResolver; - - pageInfo?: PageInfoResolver; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type EdgesResolver< - R = HostsEdges[], - Parent = HostsData, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver = Resolver< - R, - Parent, - TContext - >; - export type PageInfoResolver< - R = PageInfoPaginated, - Parent = HostsData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = HostsData, - TContext = SiemContext - > = Resolver; -} - -export namespace HostsEdgesResolvers { - export interface Resolvers { - node?: NodeResolver; - - cursor?: CursorResolver; - } - - export type NodeResolver = Resolver< - R, - Parent, - TContext - >; - export type CursorResolver< - R = CursorType, - Parent = HostsEdges, - TContext = SiemContext - > = Resolver; -} - -export namespace HostItemResolvers { - export interface Resolvers { - _id?: _IdResolver, TypeParent, TContext>; - - lastSeen?: LastSeenResolver, TypeParent, TContext>; - - host?: HostResolver, TypeParent, TContext>; - - cloud?: CloudResolver, TypeParent, TContext>; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type _IdResolver, Parent = HostItem, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type LastSeenResolver< - R = Maybe, - Parent = HostItem, - TContext = SiemContext - > = Resolver; - export type HostResolver< - R = Maybe, - Parent = HostItem, - TContext = SiemContext - > = Resolver; - export type CloudResolver< - R = Maybe, - Parent = HostItem, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = HostItem, - TContext = SiemContext - > = Resolver; -} - -export namespace CloudFieldsResolvers { - export interface Resolvers { - instance?: InstanceResolver, TypeParent, TContext>; - - machine?: MachineResolver, TypeParent, TContext>; - - provider?: ProviderResolver)[]>, TypeParent, TContext>; - - region?: RegionResolver)[]>, TypeParent, TContext>; - } - - export type InstanceResolver< - R = Maybe, - Parent = CloudFields, - TContext = SiemContext - > = Resolver; - export type MachineResolver< - R = Maybe, - Parent = CloudFields, - TContext = SiemContext - > = Resolver; - export type ProviderResolver< - R = Maybe<(Maybe)[]>, - Parent = CloudFields, - TContext = SiemContext - > = Resolver; - export type RegionResolver< - R = Maybe<(Maybe)[]>, - Parent = CloudFields, - TContext = SiemContext - > = Resolver; -} - -export namespace CloudInstanceResolvers { - export interface Resolvers { - id?: IdResolver)[]>, TypeParent, TContext>; - } - - export type IdResolver< - R = Maybe<(Maybe)[]>, - Parent = CloudInstance, - TContext = SiemContext - > = Resolver; -} - -export namespace CloudMachineResolvers { - export interface Resolvers { - type?: TypeResolver)[]>, TypeParent, TContext>; - } - - export type TypeResolver< - R = Maybe<(Maybe)[]>, - Parent = CloudMachine, - TContext = SiemContext - > = Resolver; -} - -export namespace FirstLastSeenHostResolvers { - export interface Resolvers { - inspect?: InspectResolver, TypeParent, TContext>; - - firstSeen?: FirstSeenResolver, TypeParent, TContext>; - - lastSeen?: LastSeenResolver, TypeParent, TContext>; - } - - export type InspectResolver< - R = Maybe, - Parent = FirstLastSeenHost, - TContext = SiemContext - > = Resolver; - export type FirstSeenResolver< - R = Maybe, - Parent = FirstLastSeenHost, - TContext = SiemContext - > = Resolver; - export type LastSeenResolver< - R = Maybe, - Parent = FirstLastSeenHost, - TContext = SiemContext - > = Resolver; -} - -export namespace IpOverviewDataResolvers { - export interface Resolvers { - client?: ClientResolver, TypeParent, TContext>; - - destination?: DestinationResolver, TypeParent, TContext>; - - host?: HostResolver; - - server?: ServerResolver, TypeParent, TContext>; - - source?: SourceResolver, TypeParent, TContext>; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type ClientResolver< - R = Maybe, - Parent = IpOverviewData, - TContext = SiemContext - > = Resolver; - export type DestinationResolver< - R = Maybe, - Parent = IpOverviewData, - TContext = SiemContext - > = Resolver; - export type HostResolver< - R = HostEcsFields, - Parent = IpOverviewData, - TContext = SiemContext - > = Resolver; - export type ServerResolver< - R = Maybe, - Parent = IpOverviewData, - TContext = SiemContext - > = Resolver; - export type SourceResolver< - R = Maybe, - Parent = IpOverviewData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = IpOverviewData, - TContext = SiemContext - > = Resolver; -} - -export namespace OverviewResolvers { - export interface Resolvers { - firstSeen?: FirstSeenResolver, TypeParent, TContext>; - - lastSeen?: LastSeenResolver, TypeParent, TContext>; - - autonomousSystem?: AutonomousSystemResolver; - - geo?: GeoResolver; - } - - export type FirstSeenResolver< - R = Maybe, - Parent = Overview, - TContext = SiemContext - > = Resolver; - export type LastSeenResolver< - R = Maybe, - Parent = Overview, - TContext = SiemContext - > = Resolver; - export type AutonomousSystemResolver< - R = AutonomousSystem, - Parent = Overview, - TContext = SiemContext - > = Resolver; - export type GeoResolver = Resolver< - R, - Parent, - TContext - >; -} - -export namespace AutonomousSystemResolvers { - export interface Resolvers { - number?: NumberResolver, TypeParent, TContext>; - - organization?: OrganizationResolver, TypeParent, TContext>; - } - - export type NumberResolver< - R = Maybe, - Parent = AutonomousSystem, - TContext = SiemContext - > = Resolver; - export type OrganizationResolver< - R = Maybe, - Parent = AutonomousSystem, - TContext = SiemContext - > = Resolver; -} - -export namespace AutonomousSystemOrganizationResolvers { - export interface Resolvers { - name?: NameResolver, TypeParent, TContext>; - } - - export type NameResolver< - R = Maybe, - Parent = AutonomousSystemOrganization, - TContext = SiemContext - > = Resolver; -} - -export namespace UsersDataResolvers { - export interface Resolvers { - edges?: EdgesResolver; - - totalCount?: TotalCountResolver; - - pageInfo?: PageInfoResolver; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type EdgesResolver< - R = UsersEdges[], - Parent = UsersData, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver = Resolver< - R, - Parent, - TContext - >; - export type PageInfoResolver< - R = PageInfoPaginated, - Parent = UsersData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = UsersData, - TContext = SiemContext - > = Resolver; -} - -export namespace UsersEdgesResolvers { - export interface Resolvers { - node?: NodeResolver; - - cursor?: CursorResolver; - } - - export type NodeResolver = Resolver< - R, - Parent, - TContext - >; - export type CursorResolver< - R = CursorType, - Parent = UsersEdges, - TContext = SiemContext - > = Resolver; -} - -export namespace UsersNodeResolvers { - export interface Resolvers { - _id?: _IdResolver, TypeParent, TContext>; - - timestamp?: TimestampResolver, TypeParent, TContext>; - - user?: UserResolver, TypeParent, TContext>; - } - - export type _IdResolver, Parent = UsersNode, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type TimestampResolver< - R = Maybe, - Parent = UsersNode, - TContext = SiemContext - > = Resolver; - export type UserResolver< - R = Maybe, - Parent = UsersNode, - TContext = SiemContext - > = Resolver; -} - -export namespace UsersItemResolvers { - export interface Resolvers { - name?: NameResolver, TypeParent, TContext>; - - id?: IdResolver, TypeParent, TContext>; - - groupId?: GroupIdResolver, TypeParent, TContext>; - - groupName?: GroupNameResolver, TypeParent, TContext>; - - count?: CountResolver, TypeParent, TContext>; - } - - export type NameResolver< - R = Maybe, - Parent = UsersItem, - TContext = SiemContext - > = Resolver; - export type IdResolver< - R = Maybe, - Parent = UsersItem, - TContext = SiemContext - > = Resolver; - export type GroupIdResolver< - R = Maybe, - Parent = UsersItem, - TContext = SiemContext - > = Resolver; - export type GroupNameResolver< - R = Maybe, - Parent = UsersItem, - TContext = SiemContext - > = Resolver; - export type CountResolver< - R = Maybe, - Parent = UsersItem, - TContext = SiemContext - > = Resolver; -} - -export namespace KpiNetworkDataResolvers { - export interface Resolvers { - networkEvents?: NetworkEventsResolver, TypeParent, TContext>; - - uniqueFlowId?: UniqueFlowIdResolver, TypeParent, TContext>; - - uniqueSourcePrivateIps?: UniqueSourcePrivateIpsResolver, TypeParent, TContext>; - - uniqueSourcePrivateIpsHistogram?: UniqueSourcePrivateIpsHistogramResolver< - Maybe, - TypeParent, - TContext - >; - - uniqueDestinationPrivateIps?: UniqueDestinationPrivateIpsResolver< - Maybe, - TypeParent, - TContext - >; - - uniqueDestinationPrivateIpsHistogram?: UniqueDestinationPrivateIpsHistogramResolver< - Maybe, - TypeParent, - TContext - >; - - dnsQueries?: DnsQueriesResolver, TypeParent, TContext>; - - tlsHandshakes?: TlsHandshakesResolver, TypeParent, TContext>; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type NetworkEventsResolver< - R = Maybe, - Parent = KpiNetworkData, - TContext = SiemContext - > = Resolver; - export type UniqueFlowIdResolver< - R = Maybe, - Parent = KpiNetworkData, - TContext = SiemContext - > = Resolver; - export type UniqueSourcePrivateIpsResolver< - R = Maybe, - Parent = KpiNetworkData, - TContext = SiemContext - > = Resolver; - export type UniqueSourcePrivateIpsHistogramResolver< - R = Maybe, - Parent = KpiNetworkData, - TContext = SiemContext - > = Resolver; - export type UniqueDestinationPrivateIpsResolver< - R = Maybe, - Parent = KpiNetworkData, - TContext = SiemContext - > = Resolver; - export type UniqueDestinationPrivateIpsHistogramResolver< - R = Maybe, - Parent = KpiNetworkData, - TContext = SiemContext - > = Resolver; - export type DnsQueriesResolver< - R = Maybe, - Parent = KpiNetworkData, - TContext = SiemContext - > = Resolver; - export type TlsHandshakesResolver< - R = Maybe, - Parent = KpiNetworkData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = KpiNetworkData, - TContext = SiemContext - > = Resolver; -} - -export namespace KpiNetworkHistogramDataResolvers { - export interface Resolvers { - x?: XResolver, TypeParent, TContext>; - - y?: YResolver, TypeParent, TContext>; - } - - export type XResolver< - R = Maybe, - Parent = KpiNetworkHistogramData, - TContext = SiemContext - > = Resolver; - export type YResolver< - R = Maybe, - Parent = KpiNetworkHistogramData, - TContext = SiemContext - > = Resolver; -} - -export namespace KpiHostsDataResolvers { - export interface Resolvers { - hosts?: HostsResolver, TypeParent, TContext>; - - hostsHistogram?: HostsHistogramResolver, TypeParent, TContext>; - - authSuccess?: AuthSuccessResolver, TypeParent, TContext>; - - authSuccessHistogram?: AuthSuccessHistogramResolver< - Maybe, - TypeParent, - TContext - >; - - authFailure?: AuthFailureResolver, TypeParent, TContext>; - - authFailureHistogram?: AuthFailureHistogramResolver< - Maybe, - TypeParent, - TContext - >; - - uniqueSourceIps?: UniqueSourceIpsResolver, TypeParent, TContext>; - - uniqueSourceIpsHistogram?: UniqueSourceIpsHistogramResolver< - Maybe, - TypeParent, - TContext - >; - - uniqueDestinationIps?: UniqueDestinationIpsResolver, TypeParent, TContext>; - - uniqueDestinationIpsHistogram?: UniqueDestinationIpsHistogramResolver< - Maybe, - TypeParent, - TContext - >; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type HostsResolver< - R = Maybe, - Parent = KpiHostsData, - TContext = SiemContext - > = Resolver; - export type HostsHistogramResolver< - R = Maybe, - Parent = KpiHostsData, - TContext = SiemContext - > = Resolver; - export type AuthSuccessResolver< - R = Maybe, - Parent = KpiHostsData, - TContext = SiemContext - > = Resolver; - export type AuthSuccessHistogramResolver< - R = Maybe, - Parent = KpiHostsData, - TContext = SiemContext - > = Resolver; - export type AuthFailureResolver< - R = Maybe, - Parent = KpiHostsData, - TContext = SiemContext - > = Resolver; - export type AuthFailureHistogramResolver< - R = Maybe, - Parent = KpiHostsData, - TContext = SiemContext - > = Resolver; - export type UniqueSourceIpsResolver< - R = Maybe, - Parent = KpiHostsData, - TContext = SiemContext - > = Resolver; - export type UniqueSourceIpsHistogramResolver< - R = Maybe, - Parent = KpiHostsData, - TContext = SiemContext - > = Resolver; - export type UniqueDestinationIpsResolver< - R = Maybe, - Parent = KpiHostsData, - TContext = SiemContext - > = Resolver; - export type UniqueDestinationIpsHistogramResolver< - R = Maybe, - Parent = KpiHostsData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = KpiHostsData, - TContext = SiemContext - > = Resolver; -} - -export namespace KpiHostHistogramDataResolvers { - export interface Resolvers { - x?: XResolver, TypeParent, TContext>; - - y?: YResolver, TypeParent, TContext>; - } - - export type XResolver< - R = Maybe, - Parent = KpiHostHistogramData, - TContext = SiemContext - > = Resolver; - export type YResolver< - R = Maybe, - Parent = KpiHostHistogramData, - TContext = SiemContext - > = Resolver; -} - -export namespace KpiHostDetailsDataResolvers { - export interface Resolvers { - authSuccess?: AuthSuccessResolver, TypeParent, TContext>; - - authSuccessHistogram?: AuthSuccessHistogramResolver< - Maybe, - TypeParent, - TContext - >; - - authFailure?: AuthFailureResolver, TypeParent, TContext>; - - authFailureHistogram?: AuthFailureHistogramResolver< - Maybe, - TypeParent, - TContext - >; - - uniqueSourceIps?: UniqueSourceIpsResolver, TypeParent, TContext>; - - uniqueSourceIpsHistogram?: UniqueSourceIpsHistogramResolver< - Maybe, - TypeParent, - TContext - >; - - uniqueDestinationIps?: UniqueDestinationIpsResolver, TypeParent, TContext>; - - uniqueDestinationIpsHistogram?: UniqueDestinationIpsHistogramResolver< - Maybe, - TypeParent, - TContext - >; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type AuthSuccessResolver< - R = Maybe, - Parent = KpiHostDetailsData, - TContext = SiemContext - > = Resolver; - export type AuthSuccessHistogramResolver< - R = Maybe, - Parent = KpiHostDetailsData, - TContext = SiemContext - > = Resolver; - export type AuthFailureResolver< - R = Maybe, - Parent = KpiHostDetailsData, - TContext = SiemContext - > = Resolver; - export type AuthFailureHistogramResolver< - R = Maybe, - Parent = KpiHostDetailsData, - TContext = SiemContext - > = Resolver; - export type UniqueSourceIpsResolver< - R = Maybe, - Parent = KpiHostDetailsData, - TContext = SiemContext - > = Resolver; - export type UniqueSourceIpsHistogramResolver< - R = Maybe, - Parent = KpiHostDetailsData, - TContext = SiemContext - > = Resolver; - export type UniqueDestinationIpsResolver< - R = Maybe, - Parent = KpiHostDetailsData, - TContext = SiemContext - > = Resolver; - export type UniqueDestinationIpsHistogramResolver< - R = Maybe, - Parent = KpiHostDetailsData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = KpiHostDetailsData, - TContext = SiemContext - > = Resolver; -} - -export namespace MatrixHistogramOverTimeDataResolvers { - export interface Resolvers { - inspect?: InspectResolver, TypeParent, TContext>; - - matrixHistogramData?: MatrixHistogramDataResolver< - MatrixOverTimeHistogramData[], - TypeParent, - TContext - >; - - totalCount?: TotalCountResolver; - } - - export type InspectResolver< - R = Maybe, - Parent = MatrixHistogramOverTimeData, - TContext = SiemContext - > = Resolver; - export type MatrixHistogramDataResolver< - R = MatrixOverTimeHistogramData[], - Parent = MatrixHistogramOverTimeData, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver< - R = number, - Parent = MatrixHistogramOverTimeData, - TContext = SiemContext - > = Resolver; -} - -export namespace MatrixOverTimeHistogramDataResolvers { - export interface Resolvers { - x?: XResolver, TypeParent, TContext>; - - y?: YResolver, TypeParent, TContext>; - - g?: GResolver, TypeParent, TContext>; - } - - export type XResolver< - R = Maybe, - Parent = MatrixOverTimeHistogramData, - TContext = SiemContext - > = Resolver; - export type YResolver< - R = Maybe, - Parent = MatrixOverTimeHistogramData, - TContext = SiemContext - > = Resolver; - export type GResolver< - R = Maybe, - Parent = MatrixOverTimeHistogramData, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkTopCountriesDataResolvers { - export interface Resolvers { - edges?: EdgesResolver; - - totalCount?: TotalCountResolver; - - pageInfo?: PageInfoResolver; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type EdgesResolver< - R = NetworkTopCountriesEdges[], - Parent = NetworkTopCountriesData, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver< - R = number, - Parent = NetworkTopCountriesData, - TContext = SiemContext - > = Resolver; - export type PageInfoResolver< - R = PageInfoPaginated, - Parent = NetworkTopCountriesData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = NetworkTopCountriesData, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkTopCountriesEdgesResolvers { - export interface Resolvers { - node?: NodeResolver; - - cursor?: CursorResolver; - } - - export type NodeResolver< - R = NetworkTopCountriesItem, - Parent = NetworkTopCountriesEdges, - TContext = SiemContext - > = Resolver; - export type CursorResolver< - R = CursorType, - Parent = NetworkTopCountriesEdges, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkTopCountriesItemResolvers { - export interface Resolvers { - _id?: _IdResolver, TypeParent, TContext>; - - source?: SourceResolver, TypeParent, TContext>; - - destination?: DestinationResolver, TypeParent, TContext>; - - network?: NetworkResolver, TypeParent, TContext>; - } - - export type _IdResolver< - R = Maybe, - Parent = NetworkTopCountriesItem, - TContext = SiemContext - > = Resolver; - export type SourceResolver< - R = Maybe, - Parent = NetworkTopCountriesItem, - TContext = SiemContext - > = Resolver; - export type DestinationResolver< - R = Maybe, - Parent = NetworkTopCountriesItem, - TContext = SiemContext - > = Resolver; - export type NetworkResolver< - R = Maybe, - Parent = NetworkTopCountriesItem, - TContext = SiemContext - > = Resolver; -} - -export namespace TopCountriesItemSourceResolvers { - export interface Resolvers { - country?: CountryResolver, TypeParent, TContext>; - - destination_ips?: DestinationIpsResolver, TypeParent, TContext>; - - flows?: FlowsResolver, TypeParent, TContext>; - - location?: LocationResolver, TypeParent, TContext>; - - source_ips?: SourceIpsResolver, TypeParent, TContext>; - } - - export type CountryResolver< - R = Maybe, - Parent = TopCountriesItemSource, - TContext = SiemContext - > = Resolver; - export type DestinationIpsResolver< - R = Maybe, - Parent = TopCountriesItemSource, - TContext = SiemContext - > = Resolver; - export type FlowsResolver< - R = Maybe, - Parent = TopCountriesItemSource, - TContext = SiemContext - > = Resolver; - export type LocationResolver< - R = Maybe, - Parent = TopCountriesItemSource, - TContext = SiemContext - > = Resolver; - export type SourceIpsResolver< - R = Maybe, - Parent = TopCountriesItemSource, - TContext = SiemContext - > = Resolver; -} - -export namespace GeoItemResolvers { - export interface Resolvers { - geo?: GeoResolver, TypeParent, TContext>; - - flowTarget?: FlowTargetResolver, TypeParent, TContext>; - } - - export type GeoResolver< - R = Maybe, - Parent = GeoItem, - TContext = SiemContext - > = Resolver; - export type FlowTargetResolver< - R = Maybe, - Parent = GeoItem, - TContext = SiemContext - > = Resolver; -} - -export namespace TopCountriesItemDestinationResolvers { - export interface Resolvers { - country?: CountryResolver, TypeParent, TContext>; - - destination_ips?: DestinationIpsResolver, TypeParent, TContext>; - - flows?: FlowsResolver, TypeParent, TContext>; - - location?: LocationResolver, TypeParent, TContext>; - - source_ips?: SourceIpsResolver, TypeParent, TContext>; - } - - export type CountryResolver< - R = Maybe, - Parent = TopCountriesItemDestination, - TContext = SiemContext - > = Resolver; - export type DestinationIpsResolver< - R = Maybe, - Parent = TopCountriesItemDestination, - TContext = SiemContext - > = Resolver; - export type FlowsResolver< - R = Maybe, - Parent = TopCountriesItemDestination, - TContext = SiemContext - > = Resolver; - export type LocationResolver< - R = Maybe, - Parent = TopCountriesItemDestination, - TContext = SiemContext - > = Resolver; - export type SourceIpsResolver< - R = Maybe, - Parent = TopCountriesItemDestination, - TContext = SiemContext - > = Resolver; -} - -export namespace TopNetworkTablesEcsFieldResolvers { - export interface Resolvers { - bytes_in?: BytesInResolver, TypeParent, TContext>; - - bytes_out?: BytesOutResolver, TypeParent, TContext>; - } - - export type BytesInResolver< - R = Maybe, - Parent = TopNetworkTablesEcsField, - TContext = SiemContext - > = Resolver; - export type BytesOutResolver< - R = Maybe, - Parent = TopNetworkTablesEcsField, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkTopNFlowDataResolvers { - export interface Resolvers { - edges?: EdgesResolver; - - totalCount?: TotalCountResolver; - - pageInfo?: PageInfoResolver; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type EdgesResolver< - R = NetworkTopNFlowEdges[], - Parent = NetworkTopNFlowData, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver< - R = number, - Parent = NetworkTopNFlowData, - TContext = SiemContext - > = Resolver; - export type PageInfoResolver< - R = PageInfoPaginated, - Parent = NetworkTopNFlowData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = NetworkTopNFlowData, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkTopNFlowEdgesResolvers { - export interface Resolvers { - node?: NodeResolver; - - cursor?: CursorResolver; - } - - export type NodeResolver< - R = NetworkTopNFlowItem, - Parent = NetworkTopNFlowEdges, - TContext = SiemContext - > = Resolver; - export type CursorResolver< - R = CursorType, - Parent = NetworkTopNFlowEdges, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkTopNFlowItemResolvers { - export interface Resolvers { - _id?: _IdResolver, TypeParent, TContext>; - - source?: SourceResolver, TypeParent, TContext>; - - destination?: DestinationResolver, TypeParent, TContext>; - - network?: NetworkResolver, TypeParent, TContext>; - } - - export type _IdResolver< - R = Maybe, - Parent = NetworkTopNFlowItem, - TContext = SiemContext - > = Resolver; - export type SourceResolver< - R = Maybe, - Parent = NetworkTopNFlowItem, - TContext = SiemContext - > = Resolver; - export type DestinationResolver< - R = Maybe, - Parent = NetworkTopNFlowItem, - TContext = SiemContext - > = Resolver; - export type NetworkResolver< - R = Maybe, - Parent = NetworkTopNFlowItem, - TContext = SiemContext - > = Resolver; -} - -export namespace TopNFlowItemSourceResolvers { - export interface Resolvers { - autonomous_system?: AutonomousSystemResolver, TypeParent, TContext>; - - domain?: DomainResolver, TypeParent, TContext>; - - ip?: IpResolver, TypeParent, TContext>; - - location?: LocationResolver, TypeParent, TContext>; - - flows?: FlowsResolver, TypeParent, TContext>; - - destination_ips?: DestinationIpsResolver, TypeParent, TContext>; - } - - export type AutonomousSystemResolver< - R = Maybe, - Parent = TopNFlowItemSource, - TContext = SiemContext - > = Resolver; - export type DomainResolver< - R = Maybe, - Parent = TopNFlowItemSource, - TContext = SiemContext - > = Resolver; - export type IpResolver< - R = Maybe, - Parent = TopNFlowItemSource, - TContext = SiemContext - > = Resolver; - export type LocationResolver< - R = Maybe, - Parent = TopNFlowItemSource, - TContext = SiemContext - > = Resolver; - export type FlowsResolver< - R = Maybe, - Parent = TopNFlowItemSource, - TContext = SiemContext - > = Resolver; - export type DestinationIpsResolver< - R = Maybe, - Parent = TopNFlowItemSource, - TContext = SiemContext - > = Resolver; -} - -export namespace AutonomousSystemItemResolvers { - export interface Resolvers { - name?: NameResolver, TypeParent, TContext>; - - number?: NumberResolver, TypeParent, TContext>; - } - - export type NameResolver< - R = Maybe, - Parent = AutonomousSystemItem, - TContext = SiemContext - > = Resolver; - export type NumberResolver< - R = Maybe, - Parent = AutonomousSystemItem, - TContext = SiemContext - > = Resolver; -} - -export namespace TopNFlowItemDestinationResolvers { - export interface Resolvers { - autonomous_system?: AutonomousSystemResolver, TypeParent, TContext>; - - domain?: DomainResolver, TypeParent, TContext>; - - ip?: IpResolver, TypeParent, TContext>; - - location?: LocationResolver, TypeParent, TContext>; - - flows?: FlowsResolver, TypeParent, TContext>; - - source_ips?: SourceIpsResolver, TypeParent, TContext>; - } - - export type AutonomousSystemResolver< - R = Maybe, - Parent = TopNFlowItemDestination, - TContext = SiemContext - > = Resolver; - export type DomainResolver< - R = Maybe, - Parent = TopNFlowItemDestination, - TContext = SiemContext - > = Resolver; - export type IpResolver< - R = Maybe, - Parent = TopNFlowItemDestination, - TContext = SiemContext - > = Resolver; - export type LocationResolver< - R = Maybe, - Parent = TopNFlowItemDestination, - TContext = SiemContext - > = Resolver; - export type FlowsResolver< - R = Maybe, - Parent = TopNFlowItemDestination, - TContext = SiemContext - > = Resolver; - export type SourceIpsResolver< - R = Maybe, - Parent = TopNFlowItemDestination, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkDnsDataResolvers { - export interface Resolvers { - edges?: EdgesResolver; - - totalCount?: TotalCountResolver; - - pageInfo?: PageInfoResolver; - - inspect?: InspectResolver, TypeParent, TContext>; - - histogram?: HistogramResolver, TypeParent, TContext>; - } - - export type EdgesResolver< - R = NetworkDnsEdges[], - Parent = NetworkDnsData, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver< - R = number, - Parent = NetworkDnsData, - TContext = SiemContext - > = Resolver; - export type PageInfoResolver< - R = PageInfoPaginated, - Parent = NetworkDnsData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = NetworkDnsData, - TContext = SiemContext - > = Resolver; - export type HistogramResolver< - R = Maybe, - Parent = NetworkDnsData, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkDnsEdgesResolvers { - export interface Resolvers { - node?: NodeResolver; - - cursor?: CursorResolver; - } - - export type NodeResolver< - R = NetworkDnsItem, - Parent = NetworkDnsEdges, - TContext = SiemContext - > = Resolver; - export type CursorResolver< - R = CursorType, - Parent = NetworkDnsEdges, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkDnsItemResolvers { - export interface Resolvers { - _id?: _IdResolver, TypeParent, TContext>; - - dnsBytesIn?: DnsBytesInResolver, TypeParent, TContext>; - - dnsBytesOut?: DnsBytesOutResolver, TypeParent, TContext>; - - dnsName?: DnsNameResolver, TypeParent, TContext>; - - queryCount?: QueryCountResolver, TypeParent, TContext>; - - uniqueDomains?: UniqueDomainsResolver, TypeParent, TContext>; - } - - export type _IdResolver< - R = Maybe, - Parent = NetworkDnsItem, - TContext = SiemContext - > = Resolver; - export type DnsBytesInResolver< - R = Maybe, - Parent = NetworkDnsItem, - TContext = SiemContext - > = Resolver; - export type DnsBytesOutResolver< - R = Maybe, - Parent = NetworkDnsItem, - TContext = SiemContext - > = Resolver; - export type DnsNameResolver< - R = Maybe, - Parent = NetworkDnsItem, - TContext = SiemContext - > = Resolver; - export type QueryCountResolver< - R = Maybe, - Parent = NetworkDnsItem, - TContext = SiemContext - > = Resolver; - export type UniqueDomainsResolver< - R = Maybe, - Parent = NetworkDnsItem, - TContext = SiemContext - > = Resolver; -} - -export namespace MatrixOverOrdinalHistogramDataResolvers { - export interface Resolvers { - x?: XResolver; - - y?: YResolver; - - g?: GResolver; - } - - export type XResolver< - R = string, - Parent = MatrixOverOrdinalHistogramData, - TContext = SiemContext - > = Resolver; - export type YResolver< - R = number, - Parent = MatrixOverOrdinalHistogramData, - TContext = SiemContext - > = Resolver; - export type GResolver< - R = string, - Parent = MatrixOverOrdinalHistogramData, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkDsOverTimeDataResolvers { - export interface Resolvers { - inspect?: InspectResolver, TypeParent, TContext>; - - matrixHistogramData?: MatrixHistogramDataResolver< - MatrixOverTimeHistogramData[], - TypeParent, - TContext - >; - - totalCount?: TotalCountResolver; - } - - export type InspectResolver< - R = Maybe, - Parent = NetworkDsOverTimeData, - TContext = SiemContext - > = Resolver; - export type MatrixHistogramDataResolver< - R = MatrixOverTimeHistogramData[], - Parent = NetworkDsOverTimeData, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver< - R = number, - Parent = NetworkDsOverTimeData, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkHttpDataResolvers { - export interface Resolvers { - edges?: EdgesResolver; - - totalCount?: TotalCountResolver; - - pageInfo?: PageInfoResolver; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type EdgesResolver< - R = NetworkHttpEdges[], - Parent = NetworkHttpData, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver< - R = number, - Parent = NetworkHttpData, - TContext = SiemContext - > = Resolver; - export type PageInfoResolver< - R = PageInfoPaginated, - Parent = NetworkHttpData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = NetworkHttpData, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkHttpEdgesResolvers { - export interface Resolvers { - node?: NodeResolver; - - cursor?: CursorResolver; - } - - export type NodeResolver< - R = NetworkHttpItem, - Parent = NetworkHttpEdges, - TContext = SiemContext - > = Resolver; - export type CursorResolver< - R = CursorType, - Parent = NetworkHttpEdges, - TContext = SiemContext - > = Resolver; -} - -export namespace NetworkHttpItemResolvers { - export interface Resolvers { - _id?: _IdResolver, TypeParent, TContext>; - - domains?: DomainsResolver; - - lastHost?: LastHostResolver, TypeParent, TContext>; - - lastSourceIp?: LastSourceIpResolver, TypeParent, TContext>; - - methods?: MethodsResolver; - - path?: PathResolver, TypeParent, TContext>; - - requestCount?: RequestCountResolver, TypeParent, TContext>; - - statuses?: StatusesResolver; - } - - export type _IdResolver< - R = Maybe, - Parent = NetworkHttpItem, - TContext = SiemContext - > = Resolver; - export type DomainsResolver< - R = string[], - Parent = NetworkHttpItem, - TContext = SiemContext - > = Resolver; - export type LastHostResolver< - R = Maybe, - Parent = NetworkHttpItem, - TContext = SiemContext - > = Resolver; - export type LastSourceIpResolver< - R = Maybe, - Parent = NetworkHttpItem, - TContext = SiemContext - > = Resolver; - export type MethodsResolver< - R = string[], - Parent = NetworkHttpItem, - TContext = SiemContext - > = Resolver; - export type PathResolver< - R = Maybe, - Parent = NetworkHttpItem, - TContext = SiemContext - > = Resolver; - export type RequestCountResolver< - R = Maybe, - Parent = NetworkHttpItem, - TContext = SiemContext - > = Resolver; - export type StatusesResolver< - R = string[], - Parent = NetworkHttpItem, - TContext = SiemContext - > = Resolver; -} - -export namespace OverviewNetworkDataResolvers { - export interface Resolvers { - auditbeatSocket?: AuditbeatSocketResolver, TypeParent, TContext>; - - filebeatCisco?: FilebeatCiscoResolver, TypeParent, TContext>; - - filebeatNetflow?: FilebeatNetflowResolver, TypeParent, TContext>; - - filebeatPanw?: FilebeatPanwResolver, TypeParent, TContext>; - - filebeatSuricata?: FilebeatSuricataResolver, TypeParent, TContext>; - - filebeatZeek?: FilebeatZeekResolver, TypeParent, TContext>; - - packetbeatDNS?: PacketbeatDnsResolver, TypeParent, TContext>; - - packetbeatFlow?: PacketbeatFlowResolver, TypeParent, TContext>; - - packetbeatTLS?: PacketbeatTlsResolver, TypeParent, TContext>; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type AuditbeatSocketResolver< - R = Maybe, - Parent = OverviewNetworkData, - TContext = SiemContext - > = Resolver; - export type FilebeatCiscoResolver< - R = Maybe, - Parent = OverviewNetworkData, - TContext = SiemContext - > = Resolver; - export type FilebeatNetflowResolver< - R = Maybe, - Parent = OverviewNetworkData, - TContext = SiemContext - > = Resolver; - export type FilebeatPanwResolver< - R = Maybe, - Parent = OverviewNetworkData, - TContext = SiemContext - > = Resolver; - export type FilebeatSuricataResolver< - R = Maybe, - Parent = OverviewNetworkData, - TContext = SiemContext - > = Resolver; - export type FilebeatZeekResolver< - R = Maybe, - Parent = OverviewNetworkData, - TContext = SiemContext - > = Resolver; - export type PacketbeatDnsResolver< - R = Maybe, - Parent = OverviewNetworkData, - TContext = SiemContext - > = Resolver; - export type PacketbeatFlowResolver< - R = Maybe, - Parent = OverviewNetworkData, - TContext = SiemContext - > = Resolver; - export type PacketbeatTlsResolver< - R = Maybe, - Parent = OverviewNetworkData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = OverviewNetworkData, - TContext = SiemContext - > = Resolver; -} - -export namespace OverviewHostDataResolvers { - export interface Resolvers { - auditbeatAuditd?: AuditbeatAuditdResolver, TypeParent, TContext>; - - auditbeatFIM?: AuditbeatFimResolver, TypeParent, TContext>; - - auditbeatLogin?: AuditbeatLoginResolver, TypeParent, TContext>; - - auditbeatPackage?: AuditbeatPackageResolver, TypeParent, TContext>; - - auditbeatProcess?: AuditbeatProcessResolver, TypeParent, TContext>; - - auditbeatUser?: AuditbeatUserResolver, TypeParent, TContext>; - - endgameDns?: EndgameDnsResolver, TypeParent, TContext>; - - endgameFile?: EndgameFileResolver, TypeParent, TContext>; - - endgameImageLoad?: EndgameImageLoadResolver, TypeParent, TContext>; - - endgameNetwork?: EndgameNetworkResolver, TypeParent, TContext>; - - endgameProcess?: EndgameProcessResolver, TypeParent, TContext>; - - endgameRegistry?: EndgameRegistryResolver, TypeParent, TContext>; - - endgameSecurity?: EndgameSecurityResolver, TypeParent, TContext>; - - filebeatSystemModule?: FilebeatSystemModuleResolver, TypeParent, TContext>; - - winlogbeatSecurity?: WinlogbeatSecurityResolver, TypeParent, TContext>; - - winlogbeatMWSysmonOperational?: WinlogbeatMwSysmonOperationalResolver< - Maybe, - TypeParent, - TContext - >; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type AuditbeatAuditdResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type AuditbeatFimResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type AuditbeatLoginResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type AuditbeatPackageResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type AuditbeatProcessResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type AuditbeatUserResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type EndgameDnsResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type EndgameFileResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type EndgameImageLoadResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type EndgameNetworkResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type EndgameProcessResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type EndgameRegistryResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type EndgameSecurityResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type FilebeatSystemModuleResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type WinlogbeatSecurityResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type WinlogbeatMwSysmonOperationalResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = OverviewHostData, - TContext = SiemContext - > = Resolver; -} - -export namespace TlsDataResolvers { - export interface Resolvers { - edges?: EdgesResolver; - - totalCount?: TotalCountResolver; - - pageInfo?: PageInfoResolver; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type EdgesResolver = Resolver< - R, - Parent, - TContext - >; - export type TotalCountResolver = Resolver< - R, - Parent, - TContext - >; - export type PageInfoResolver< - R = PageInfoPaginated, - Parent = TlsData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = TlsData, - TContext = SiemContext - > = Resolver; -} - -export namespace TlsEdgesResolvers { - export interface Resolvers { - node?: NodeResolver; - - cursor?: CursorResolver; - } - - export type NodeResolver = Resolver< - R, - Parent, - TContext - >; - export type CursorResolver = Resolver< - R, - Parent, - TContext - >; -} - -export namespace TlsNodeResolvers { - export interface Resolvers { - _id?: _IdResolver, TypeParent, TContext>; - - timestamp?: TimestampResolver, TypeParent, TContext>; - - alternativeNames?: AlternativeNamesResolver, TypeParent, TContext>; - - notAfter?: NotAfterResolver, TypeParent, TContext>; - - commonNames?: CommonNamesResolver, TypeParent, TContext>; - - ja3?: Ja3Resolver, TypeParent, TContext>; - - issuerNames?: IssuerNamesResolver, TypeParent, TContext>; - } - - export type _IdResolver, Parent = TlsNode, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type TimestampResolver< - R = Maybe, - Parent = TlsNode, - TContext = SiemContext - > = Resolver; - export type AlternativeNamesResolver< - R = Maybe, - Parent = TlsNode, - TContext = SiemContext - > = Resolver; - export type NotAfterResolver< - R = Maybe, - Parent = TlsNode, - TContext = SiemContext - > = Resolver; - export type CommonNamesResolver< - R = Maybe, - Parent = TlsNode, - TContext = SiemContext - > = Resolver; - export type Ja3Resolver, Parent = TlsNode, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type IssuerNamesResolver< - R = Maybe, - Parent = TlsNode, - TContext = SiemContext - > = Resolver; -} - -export namespace UncommonProcessesDataResolvers { - export interface Resolvers { - edges?: EdgesResolver; - - totalCount?: TotalCountResolver; - - pageInfo?: PageInfoResolver; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type EdgesResolver< - R = UncommonProcessesEdges[], - Parent = UncommonProcessesData, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver< - R = number, - Parent = UncommonProcessesData, - TContext = SiemContext - > = Resolver; - export type PageInfoResolver< - R = PageInfoPaginated, - Parent = UncommonProcessesData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = UncommonProcessesData, - TContext = SiemContext - > = Resolver; -} - -export namespace UncommonProcessesEdgesResolvers { - export interface Resolvers { - node?: NodeResolver; - - cursor?: CursorResolver; - } - - export type NodeResolver< - R = UncommonProcessItem, - Parent = UncommonProcessesEdges, - TContext = SiemContext - > = Resolver; - export type CursorResolver< - R = CursorType, - Parent = UncommonProcessesEdges, - TContext = SiemContext - > = Resolver; -} - -export namespace UncommonProcessItemResolvers { - export interface Resolvers { - _id?: _IdResolver; - - instances?: InstancesResolver; - - process?: ProcessResolver; - - hosts?: HostsResolver; - - user?: UserResolver, TypeParent, TContext>; - } - - export type _IdResolver< - R = string, - Parent = UncommonProcessItem, - TContext = SiemContext - > = Resolver; - export type InstancesResolver< - R = number, - Parent = UncommonProcessItem, - TContext = SiemContext - > = Resolver; - export type ProcessResolver< - R = ProcessEcsFields, - Parent = UncommonProcessItem, - TContext = SiemContext - > = Resolver; - export type HostsResolver< - R = HostEcsFields[], - Parent = UncommonProcessItem, - TContext = SiemContext - > = Resolver; - export type UserResolver< - R = Maybe, - Parent = UncommonProcessItem, - TContext = SiemContext - > = Resolver; -} - -export namespace SayMyNameResolvers { - export interface Resolvers { - /** The id of the source */ - appName?: AppNameResolver; - } - - export type AppNameResolver = Resolver< - R, - Parent, - TContext - >; -} - -export namespace TimelineResultResolvers { - export interface Resolvers { - columns?: ColumnsResolver, TypeParent, TContext>; - - created?: CreatedResolver, TypeParent, TContext>; - - createdBy?: CreatedByResolver, TypeParent, TContext>; - - dataProviders?: DataProvidersResolver, TypeParent, TContext>; - - dateRange?: DateRangeResolver, TypeParent, TContext>; - - description?: DescriptionResolver, TypeParent, TContext>; - - eventIdToNoteIds?: EventIdToNoteIdsResolver, TypeParent, TContext>; - - eventType?: EventTypeResolver, TypeParent, TContext>; - - favorite?: FavoriteResolver, TypeParent, TContext>; - - filters?: FiltersResolver, TypeParent, TContext>; - - kqlMode?: KqlModeResolver, TypeParent, TContext>; - - kqlQuery?: KqlQueryResolver, TypeParent, TContext>; - - notes?: NotesResolver, TypeParent, TContext>; - - noteIds?: NoteIdsResolver, TypeParent, TContext>; - - pinnedEventIds?: PinnedEventIdsResolver, TypeParent, TContext>; - - pinnedEventsSaveObject?: PinnedEventsSaveObjectResolver< - Maybe, - TypeParent, - TContext - >; - - savedQueryId?: SavedQueryIdResolver, TypeParent, TContext>; - - savedObjectId?: SavedObjectIdResolver; - - sort?: SortResolver, TypeParent, TContext>; - - title?: TitleResolver, TypeParent, TContext>; - - updated?: UpdatedResolver, TypeParent, TContext>; - - updatedBy?: UpdatedByResolver, TypeParent, TContext>; - - version?: VersionResolver; - } - - export type ColumnsResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type CreatedResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type CreatedByResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type DataProvidersResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type DateRangeResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type DescriptionResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type EventIdToNoteIdsResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type EventTypeResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type FavoriteResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type FiltersResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type KqlModeResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type KqlQueryResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type NotesResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type NoteIdsResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type PinnedEventIdsResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type PinnedEventsSaveObjectResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type SavedQueryIdResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type SavedObjectIdResolver< - R = string, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type SortResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type TitleResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type UpdatedResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type UpdatedByResolver< - R = Maybe, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; - export type VersionResolver< - R = string, - Parent = TimelineResult, - TContext = SiemContext - > = Resolver; -} - -export namespace ColumnHeaderResultResolvers { - export interface Resolvers { - aggregatable?: AggregatableResolver, TypeParent, TContext>; - - category?: CategoryResolver, TypeParent, TContext>; - - columnHeaderType?: ColumnHeaderTypeResolver, TypeParent, TContext>; - - description?: DescriptionResolver, TypeParent, TContext>; - - example?: ExampleResolver, TypeParent, TContext>; - - indexes?: IndexesResolver, TypeParent, TContext>; - - id?: IdResolver, TypeParent, TContext>; - - name?: NameResolver, TypeParent, TContext>; - - placeholder?: PlaceholderResolver, TypeParent, TContext>; - - searchable?: SearchableResolver, TypeParent, TContext>; - - type?: TypeResolver, TypeParent, TContext>; - } - - export type AggregatableResolver< - R = Maybe, - Parent = ColumnHeaderResult, - TContext = SiemContext - > = Resolver; - export type CategoryResolver< - R = Maybe, - Parent = ColumnHeaderResult, - TContext = SiemContext - > = Resolver; - export type ColumnHeaderTypeResolver< - R = Maybe, - Parent = ColumnHeaderResult, - TContext = SiemContext - > = Resolver; - export type DescriptionResolver< - R = Maybe, - Parent = ColumnHeaderResult, - TContext = SiemContext - > = Resolver; - export type ExampleResolver< - R = Maybe, - Parent = ColumnHeaderResult, - TContext = SiemContext - > = Resolver; - export type IndexesResolver< - R = Maybe, - Parent = ColumnHeaderResult, - TContext = SiemContext - > = Resolver; - export type IdResolver< - R = Maybe, - Parent = ColumnHeaderResult, - TContext = SiemContext - > = Resolver; - export type NameResolver< - R = Maybe, - Parent = ColumnHeaderResult, - TContext = SiemContext - > = Resolver; - export type PlaceholderResolver< - R = Maybe, - Parent = ColumnHeaderResult, - TContext = SiemContext - > = Resolver; - export type SearchableResolver< - R = Maybe, - Parent = ColumnHeaderResult, - TContext = SiemContext - > = Resolver; - export type TypeResolver< - R = Maybe, - Parent = ColumnHeaderResult, - TContext = SiemContext - > = Resolver; -} - -export namespace DataProviderResultResolvers { - export interface Resolvers { - id?: IdResolver, TypeParent, TContext>; - - name?: NameResolver, TypeParent, TContext>; - - enabled?: EnabledResolver, TypeParent, TContext>; - - excluded?: ExcludedResolver, TypeParent, TContext>; - - kqlQuery?: KqlQueryResolver, TypeParent, TContext>; - - queryMatch?: QueryMatchResolver, TypeParent, TContext>; - - and?: AndResolver, TypeParent, TContext>; - } - - export type IdResolver< - R = Maybe, - Parent = DataProviderResult, - TContext = SiemContext - > = Resolver; - export type NameResolver< - R = Maybe, - Parent = DataProviderResult, - TContext = SiemContext - > = Resolver; - export type EnabledResolver< - R = Maybe, - Parent = DataProviderResult, - TContext = SiemContext - > = Resolver; - export type ExcludedResolver< - R = Maybe, - Parent = DataProviderResult, - TContext = SiemContext - > = Resolver; - export type KqlQueryResolver< - R = Maybe, - Parent = DataProviderResult, - TContext = SiemContext - > = Resolver; - export type QueryMatchResolver< - R = Maybe, - Parent = DataProviderResult, - TContext = SiemContext - > = Resolver; - export type AndResolver< - R = Maybe, - Parent = DataProviderResult, - TContext = SiemContext - > = Resolver; -} - -export namespace QueryMatchResultResolvers { - export interface Resolvers { - field?: FieldResolver, TypeParent, TContext>; - - displayField?: DisplayFieldResolver, TypeParent, TContext>; - - value?: ValueResolver, TypeParent, TContext>; - - displayValue?: DisplayValueResolver, TypeParent, TContext>; - - operator?: OperatorResolver, TypeParent, TContext>; - } - - export type FieldResolver< - R = Maybe, - Parent = QueryMatchResult, - TContext = SiemContext - > = Resolver; - export type DisplayFieldResolver< - R = Maybe, - Parent = QueryMatchResult, - TContext = SiemContext - > = Resolver; - export type ValueResolver< - R = Maybe, - Parent = QueryMatchResult, - TContext = SiemContext - > = Resolver; - export type DisplayValueResolver< - R = Maybe, - Parent = QueryMatchResult, - TContext = SiemContext - > = Resolver; - export type OperatorResolver< - R = Maybe, - Parent = QueryMatchResult, - TContext = SiemContext - > = Resolver; -} - -export namespace DateRangePickerResultResolvers { - export interface Resolvers { - start?: StartResolver, TypeParent, TContext>; - - end?: EndResolver, TypeParent, TContext>; - } - - export type StartResolver< - R = Maybe, - Parent = DateRangePickerResult, - TContext = SiemContext - > = Resolver; - export type EndResolver< - R = Maybe, - Parent = DateRangePickerResult, - TContext = SiemContext - > = Resolver; -} - -export namespace FavoriteTimelineResultResolvers { - export interface Resolvers { - fullName?: FullNameResolver, TypeParent, TContext>; - - userName?: UserNameResolver, TypeParent, TContext>; - - favoriteDate?: FavoriteDateResolver, TypeParent, TContext>; - } - - export type FullNameResolver< - R = Maybe, - Parent = FavoriteTimelineResult, - TContext = SiemContext - > = Resolver; - export type UserNameResolver< - R = Maybe, - Parent = FavoriteTimelineResult, - TContext = SiemContext - > = Resolver; - export type FavoriteDateResolver< - R = Maybe, - Parent = FavoriteTimelineResult, - TContext = SiemContext - > = Resolver; -} - -export namespace FilterTimelineResultResolvers { - export interface Resolvers { - exists?: ExistsResolver, TypeParent, TContext>; - - meta?: MetaResolver, TypeParent, TContext>; - - match_all?: MatchAllResolver, TypeParent, TContext>; - - missing?: MissingResolver, TypeParent, TContext>; - - query?: QueryResolver, TypeParent, TContext>; - - range?: RangeResolver, TypeParent, TContext>; - - script?: ScriptResolver, TypeParent, TContext>; - } - - export type ExistsResolver< - R = Maybe, - Parent = FilterTimelineResult, - TContext = SiemContext - > = Resolver; - export type MetaResolver< - R = Maybe, - Parent = FilterTimelineResult, - TContext = SiemContext - > = Resolver; - export type MatchAllResolver< - R = Maybe, - Parent = FilterTimelineResult, - TContext = SiemContext - > = Resolver; - export type MissingResolver< - R = Maybe, - Parent = FilterTimelineResult, - TContext = SiemContext - > = Resolver; - export type QueryResolver< - R = Maybe, - Parent = FilterTimelineResult, - TContext = SiemContext - > = Resolver; - export type RangeResolver< - R = Maybe, - Parent = FilterTimelineResult, - TContext = SiemContext - > = Resolver; - export type ScriptResolver< - R = Maybe, - Parent = FilterTimelineResult, - TContext = SiemContext - > = Resolver; -} - -export namespace FilterMetaTimelineResultResolvers { - export interface Resolvers { - alias?: AliasResolver, TypeParent, TContext>; - - controlledBy?: ControlledByResolver, TypeParent, TContext>; - - disabled?: DisabledResolver, TypeParent, TContext>; - - field?: FieldResolver, TypeParent, TContext>; - - formattedValue?: FormattedValueResolver, TypeParent, TContext>; - - index?: IndexResolver, TypeParent, TContext>; - - key?: KeyResolver, TypeParent, TContext>; - - negate?: NegateResolver, TypeParent, TContext>; - - params?: ParamsResolver, TypeParent, TContext>; - - type?: TypeResolver, TypeParent, TContext>; - - value?: ValueResolver, TypeParent, TContext>; - } - - export type AliasResolver< - R = Maybe, - Parent = FilterMetaTimelineResult, - TContext = SiemContext - > = Resolver; - export type ControlledByResolver< - R = Maybe, - Parent = FilterMetaTimelineResult, - TContext = SiemContext - > = Resolver; - export type DisabledResolver< - R = Maybe, - Parent = FilterMetaTimelineResult, - TContext = SiemContext - > = Resolver; - export type FieldResolver< - R = Maybe, - Parent = FilterMetaTimelineResult, - TContext = SiemContext - > = Resolver; - export type FormattedValueResolver< - R = Maybe, - Parent = FilterMetaTimelineResult, - TContext = SiemContext - > = Resolver; - export type IndexResolver< - R = Maybe, - Parent = FilterMetaTimelineResult, - TContext = SiemContext - > = Resolver; - export type KeyResolver< - R = Maybe, - Parent = FilterMetaTimelineResult, - TContext = SiemContext - > = Resolver; - export type NegateResolver< - R = Maybe, - Parent = FilterMetaTimelineResult, - TContext = SiemContext - > = Resolver; - export type ParamsResolver< - R = Maybe, - Parent = FilterMetaTimelineResult, - TContext = SiemContext - > = Resolver; - export type TypeResolver< - R = Maybe, - Parent = FilterMetaTimelineResult, - TContext = SiemContext - > = Resolver; - export type ValueResolver< - R = Maybe, - Parent = FilterMetaTimelineResult, - TContext = SiemContext - > = Resolver; -} - -export namespace SerializedFilterQueryResultResolvers { - export interface Resolvers { - filterQuery?: FilterQueryResolver, TypeParent, TContext>; - } - - export type FilterQueryResolver< - R = Maybe, - Parent = SerializedFilterQueryResult, - TContext = SiemContext - > = Resolver; -} - -export namespace SerializedKueryQueryResultResolvers { - export interface Resolvers { - kuery?: KueryResolver, TypeParent, TContext>; - - serializedQuery?: SerializedQueryResolver, TypeParent, TContext>; - } - - export type KueryResolver< - R = Maybe, - Parent = SerializedKueryQueryResult, - TContext = SiemContext - > = Resolver; - export type SerializedQueryResolver< - R = Maybe, - Parent = SerializedKueryQueryResult, - TContext = SiemContext - > = Resolver; -} - -export namespace KueryFilterQueryResultResolvers { - export interface Resolvers { - kind?: KindResolver, TypeParent, TContext>; - - expression?: ExpressionResolver, TypeParent, TContext>; - } - - export type KindResolver< - R = Maybe, - Parent = KueryFilterQueryResult, - TContext = SiemContext - > = Resolver; - export type ExpressionResolver< - R = Maybe, - Parent = KueryFilterQueryResult, - TContext = SiemContext - > = Resolver; -} - -export namespace SortTimelineResultResolvers { - export interface Resolvers { - columnId?: ColumnIdResolver, TypeParent, TContext>; - - sortDirection?: SortDirectionResolver, TypeParent, TContext>; - } - - export type ColumnIdResolver< - R = Maybe, - Parent = SortTimelineResult, - TContext = SiemContext - > = Resolver; - export type SortDirectionResolver< - R = Maybe, - Parent = SortTimelineResult, - TContext = SiemContext - > = Resolver; -} - -export namespace ResponseTimelinesResolvers { - export interface Resolvers { - timeline?: TimelineResolver<(Maybe)[], TypeParent, TContext>; - - totalCount?: TotalCountResolver, TypeParent, TContext>; - } - - export type TimelineResolver< - R = (Maybe)[], - Parent = ResponseTimelines, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver< - R = Maybe, - Parent = ResponseTimelines, - TContext = SiemContext - > = Resolver; -} - -export namespace MutationResolvers { - export interface Resolvers { - /** Persists a note */ - persistNote?: PersistNoteResolver; - - deleteNote?: DeleteNoteResolver, TypeParent, TContext>; - - deleteNoteByTimelineId?: DeleteNoteByTimelineIdResolver, TypeParent, TContext>; - /** Persists a pinned event in a timeline */ - persistPinnedEventOnTimeline?: PersistPinnedEventOnTimelineResolver< - Maybe, - TypeParent, - TContext - >; - /** Remove a pinned events in a timeline */ - deletePinnedEventOnTimeline?: DeletePinnedEventOnTimelineResolver< - boolean, - TypeParent, - TContext - >; - /** Remove all pinned events in a timeline */ - deleteAllPinnedEventsOnTimeline?: DeleteAllPinnedEventsOnTimelineResolver< - boolean, - TypeParent, - TContext - >; - /** Persists a timeline */ - persistTimeline?: PersistTimelineResolver; - - persistFavorite?: PersistFavoriteResolver; - - deleteTimeline?: DeleteTimelineResolver; - } - - export type PersistNoteResolver = Resolver< - R, - Parent, - TContext, - PersistNoteArgs - >; - export interface PersistNoteArgs { - noteId?: Maybe; - - version?: Maybe; - - note: NoteInput; - } - - export type DeleteNoteResolver< - R = Maybe, - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface DeleteNoteArgs { - id: string[]; - } - - export type DeleteNoteByTimelineIdResolver< - R = Maybe, - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface DeleteNoteByTimelineIdArgs { - timelineId: string; - - version?: Maybe; - } - - export type PersistPinnedEventOnTimelineResolver< - R = Maybe, - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface PersistPinnedEventOnTimelineArgs { - pinnedEventId?: Maybe; - - eventId: string; - - timelineId?: Maybe; - } - - export type DeletePinnedEventOnTimelineResolver< - R = boolean, - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface DeletePinnedEventOnTimelineArgs { - id: string[]; - } - - export type DeleteAllPinnedEventsOnTimelineResolver< - R = boolean, - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface DeleteAllPinnedEventsOnTimelineArgs { - timelineId: string; - } - - export type PersistTimelineResolver< - R = ResponseTimeline, - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface PersistTimelineArgs { - id?: Maybe; - - version?: Maybe; - - timeline: TimelineInput; - } - - export type PersistFavoriteResolver< - R = ResponseFavoriteTimeline, - Parent = {}, - TContext = SiemContext - > = Resolver; - export interface PersistFavoriteArgs { - timelineId?: Maybe; - } - - export type DeleteTimelineResolver = Resolver< - R, - Parent, - TContext, - DeleteTimelineArgs - >; - export interface DeleteTimelineArgs { - id: string[]; - } -} - -export namespace ResponseNoteResolvers { - export interface Resolvers { - code?: CodeResolver, TypeParent, TContext>; - - message?: MessageResolver, TypeParent, TContext>; - - note?: NoteResolver; - } - - export type CodeResolver< - R = Maybe, - Parent = ResponseNote, - TContext = SiemContext - > = Resolver; - export type MessageResolver< - R = Maybe, - Parent = ResponseNote, - TContext = SiemContext - > = Resolver; - export type NoteResolver< - R = NoteResult, - Parent = ResponseNote, - TContext = SiemContext - > = Resolver; -} - -export namespace ResponseTimelineResolvers { - export interface Resolvers { - code?: CodeResolver, TypeParent, TContext>; - - message?: MessageResolver, TypeParent, TContext>; - - timeline?: TimelineResolver; - } - - export type CodeResolver< - R = Maybe, - Parent = ResponseTimeline, - TContext = SiemContext - > = Resolver; - export type MessageResolver< - R = Maybe, - Parent = ResponseTimeline, - TContext = SiemContext - > = Resolver; - export type TimelineResolver< - R = TimelineResult, - Parent = ResponseTimeline, - TContext = SiemContext - > = Resolver; -} - -export namespace ResponseFavoriteTimelineResolvers { - export interface Resolvers { - code?: CodeResolver, TypeParent, TContext>; - - message?: MessageResolver, TypeParent, TContext>; - - savedObjectId?: SavedObjectIdResolver; - - version?: VersionResolver; - - favorite?: FavoriteResolver, TypeParent, TContext>; - } - - export type CodeResolver< - R = Maybe, - Parent = ResponseFavoriteTimeline, - TContext = SiemContext - > = Resolver; - export type MessageResolver< - R = Maybe, - Parent = ResponseFavoriteTimeline, - TContext = SiemContext - > = Resolver; - export type SavedObjectIdResolver< - R = string, - Parent = ResponseFavoriteTimeline, - TContext = SiemContext - > = Resolver; - export type VersionResolver< - R = string, - Parent = ResponseFavoriteTimeline, - TContext = SiemContext - > = Resolver; - export type FavoriteResolver< - R = Maybe, - Parent = ResponseFavoriteTimeline, - TContext = SiemContext - > = Resolver; -} - -export namespace EcsEdgesResolvers { - export interface Resolvers { - node?: NodeResolver; - - cursor?: CursorResolver; - } - - export type NodeResolver = Resolver< - R, - Parent, - TContext - >; - export type CursorResolver = Resolver< - R, - Parent, - TContext - >; -} - -export namespace EventsTimelineDataResolvers { - export interface Resolvers { - edges?: EdgesResolver; - - totalCount?: TotalCountResolver; - - pageInfo?: PageInfoResolver; - - inspect?: InspectResolver, TypeParent, TContext>; - } - - export type EdgesResolver< - R = EcsEdges[], - Parent = EventsTimelineData, - TContext = SiemContext - > = Resolver; - export type TotalCountResolver< - R = number, - Parent = EventsTimelineData, - TContext = SiemContext - > = Resolver; - export type PageInfoResolver< - R = PageInfo, - Parent = EventsTimelineData, - TContext = SiemContext - > = Resolver; - export type InspectResolver< - R = Maybe, - Parent = EventsTimelineData, - TContext = SiemContext - > = Resolver; -} - -export namespace OsFieldsResolvers { - export interface Resolvers { - platform?: PlatformResolver, TypeParent, TContext>; - - name?: NameResolver, TypeParent, TContext>; - - full?: FullResolver, TypeParent, TContext>; - - family?: FamilyResolver, TypeParent, TContext>; - - version?: VersionResolver, TypeParent, TContext>; - - kernel?: KernelResolver, TypeParent, TContext>; - } - - export type PlatformResolver< - R = Maybe, - Parent = OsFields, - TContext = SiemContext - > = Resolver; - export type NameResolver, Parent = OsFields, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type FullResolver, Parent = OsFields, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type FamilyResolver< - R = Maybe, - Parent = OsFields, - TContext = SiemContext - > = Resolver; - export type VersionResolver< - R = Maybe, - Parent = OsFields, - TContext = SiemContext - > = Resolver; - export type KernelResolver< - R = Maybe, - Parent = OsFields, - TContext = SiemContext - > = Resolver; -} - -export namespace HostFieldsResolvers { - export interface Resolvers { - architecture?: ArchitectureResolver, TypeParent, TContext>; - - id?: IdResolver, TypeParent, TContext>; - - ip?: IpResolver)[]>, TypeParent, TContext>; - - mac?: MacResolver)[]>, TypeParent, TContext>; - - name?: NameResolver, TypeParent, TContext>; - - os?: OsResolver, TypeParent, TContext>; - - type?: TypeResolver, TypeParent, TContext>; - } - - export type ArchitectureResolver< - R = Maybe, - Parent = HostFields, - TContext = SiemContext - > = Resolver; - export type IdResolver, Parent = HostFields, TContext = SiemContext> = Resolver< - R, - Parent, - TContext - >; - export type IpResolver< - R = Maybe<(Maybe)[]>, - Parent = HostFields, - TContext = SiemContext - > = Resolver; - export type MacResolver< - R = Maybe<(Maybe)[]>, - Parent = HostFields, - TContext = SiemContext - > = Resolver; - export type NameResolver< - R = Maybe, - Parent = HostFields, - TContext = SiemContext - > = Resolver; - export type OsResolver< - R = Maybe, - Parent = HostFields, - TContext = SiemContext - > = Resolver; - export type TypeResolver< - R = Maybe, - Parent = HostFields, - TContext = SiemContext - > = Resolver; -} - -/** Directs the executor to skip this field or fragment when the `if` argument is true. */ -export type SkipDirectiveResolver = DirectiveResolverFn< - Result, - SkipDirectiveArgs, - SiemContext ->; -export interface SkipDirectiveArgs { - /** Skipped when true. */ - if: boolean; -} - -/** Directs the executor to include this field or fragment only when the `if` argument is true. */ -export type IncludeDirectiveResolver = DirectiveResolverFn< - Result, - IncludeDirectiveArgs, - SiemContext ->; -export interface IncludeDirectiveArgs { - /** Included when true. */ - if: boolean; -} - -/** Marks an element of a GraphQL schema as no longer supported. */ -export type DeprecatedDirectiveResolver = DirectiveResolverFn< - Result, - DeprecatedDirectiveArgs, - SiemContext ->; -export interface DeprecatedDirectiveArgs { - /** Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/). */ - reason?: string; -} - -export interface ToStringArrayScalarConfig extends GraphQLScalarTypeConfig { - name: 'ToStringArray'; -} -export interface DateScalarConfig extends GraphQLScalarTypeConfig { - name: 'Date'; -} -export interface ToNumberArrayScalarConfig extends GraphQLScalarTypeConfig { - name: 'ToNumberArray'; -} -export interface ToDateArrayScalarConfig extends GraphQLScalarTypeConfig { - name: 'ToDateArray'; -} -export interface ToBooleanArrayScalarConfig extends GraphQLScalarTypeConfig { - name: 'ToBooleanArray'; -} -export interface ToAnyScalarConfig extends GraphQLScalarTypeConfig { - name: 'ToAny'; -} -export interface EsValueScalarConfig extends GraphQLScalarTypeConfig { - name: 'EsValue'; -} - -export type IResolvers = { - Query?: QueryResolvers.Resolvers; - NoteResult?: NoteResultResolvers.Resolvers; - ResponseNotes?: ResponseNotesResolvers.Resolvers; - PinnedEvent?: PinnedEventResolvers.Resolvers; - Source?: SourceResolvers.Resolvers; - SourceConfiguration?: SourceConfigurationResolvers.Resolvers; - SourceFields?: SourceFieldsResolvers.Resolvers; - SourceStatus?: SourceStatusResolvers.Resolvers; - IndexField?: IndexFieldResolvers.Resolvers; - AuthenticationsData?: AuthenticationsDataResolvers.Resolvers; - AuthenticationsEdges?: AuthenticationsEdgesResolvers.Resolvers; - AuthenticationItem?: AuthenticationItemResolvers.Resolvers; - UserEcsFields?: UserEcsFieldsResolvers.Resolvers; - LastSourceHost?: LastSourceHostResolvers.Resolvers; - SourceEcsFields?: SourceEcsFieldsResolvers.Resolvers; - GeoEcsFields?: GeoEcsFieldsResolvers.Resolvers; - Location?: LocationResolvers.Resolvers; - HostEcsFields?: HostEcsFieldsResolvers.Resolvers; - OsEcsFields?: OsEcsFieldsResolvers.Resolvers; - CursorType?: CursorTypeResolvers.Resolvers; - PageInfoPaginated?: PageInfoPaginatedResolvers.Resolvers; - Inspect?: InspectResolvers.Resolvers; - TimelineData?: TimelineDataResolvers.Resolvers; - TimelineEdges?: TimelineEdgesResolvers.Resolvers; - TimelineItem?: TimelineItemResolvers.Resolvers; - TimelineNonEcsData?: TimelineNonEcsDataResolvers.Resolvers; - Ecs?: EcsResolvers.Resolvers; - AuditdEcsFields?: AuditdEcsFieldsResolvers.Resolvers; - AuditdData?: AuditdDataResolvers.Resolvers; - Summary?: SummaryResolvers.Resolvers; - PrimarySecondary?: PrimarySecondaryResolvers.Resolvers; - DestinationEcsFields?: DestinationEcsFieldsResolvers.Resolvers; - DnsEcsFields?: DnsEcsFieldsResolvers.Resolvers; - DnsQuestionData?: DnsQuestionDataResolvers.Resolvers; - EndgameEcsFields?: EndgameEcsFieldsResolvers.Resolvers; - EventEcsFields?: EventEcsFieldsResolvers.Resolvers; - NetworkEcsField?: NetworkEcsFieldResolvers.Resolvers; - RuleEcsField?: RuleEcsFieldResolvers.Resolvers; - SignalField?: SignalFieldResolvers.Resolvers; - RuleField?: RuleFieldResolvers.Resolvers; - SuricataEcsFields?: SuricataEcsFieldsResolvers.Resolvers; - SuricataEveData?: SuricataEveDataResolvers.Resolvers; - SuricataAlertData?: SuricataAlertDataResolvers.Resolvers; - TlsEcsFields?: TlsEcsFieldsResolvers.Resolvers; - TlsClientCertificateData?: TlsClientCertificateDataResolvers.Resolvers; - FingerprintData?: FingerprintDataResolvers.Resolvers; - TlsFingerprintsData?: TlsFingerprintsDataResolvers.Resolvers; - TlsJa3Data?: TlsJa3DataResolvers.Resolvers; - TlsServerCertificateData?: TlsServerCertificateDataResolvers.Resolvers; - ZeekEcsFields?: ZeekEcsFieldsResolvers.Resolvers; - ZeekConnectionData?: ZeekConnectionDataResolvers.Resolvers; - ZeekNoticeData?: ZeekNoticeDataResolvers.Resolvers; - ZeekDnsData?: ZeekDnsDataResolvers.Resolvers; - ZeekHttpData?: ZeekHttpDataResolvers.Resolvers; - ZeekFileData?: ZeekFileDataResolvers.Resolvers; - ZeekSslData?: ZeekSslDataResolvers.Resolvers; - HttpEcsFields?: HttpEcsFieldsResolvers.Resolvers; - HttpRequestData?: HttpRequestDataResolvers.Resolvers; - HttpBodyData?: HttpBodyDataResolvers.Resolvers; - HttpResponseData?: HttpResponseDataResolvers.Resolvers; - UrlEcsFields?: UrlEcsFieldsResolvers.Resolvers; - WinlogEcsFields?: WinlogEcsFieldsResolvers.Resolvers; - ProcessEcsFields?: ProcessEcsFieldsResolvers.Resolvers; - ProcessHashData?: ProcessHashDataResolvers.Resolvers; - Thread?: ThreadResolvers.Resolvers; - FileFields?: FileFieldsResolvers.Resolvers; - SystemEcsField?: SystemEcsFieldResolvers.Resolvers; - AuditEcsFields?: AuditEcsFieldsResolvers.Resolvers; - PackageEcsFields?: PackageEcsFieldsResolvers.Resolvers; - AuthEcsFields?: AuthEcsFieldsResolvers.Resolvers; - SshEcsFields?: SshEcsFieldsResolvers.Resolvers; - PageInfo?: PageInfoResolvers.Resolvers; - TimelineDetailsData?: TimelineDetailsDataResolvers.Resolvers; - DetailItem?: DetailItemResolvers.Resolvers; - LastEventTimeData?: LastEventTimeDataResolvers.Resolvers; - HostsData?: HostsDataResolvers.Resolvers; - HostsEdges?: HostsEdgesResolvers.Resolvers; - HostItem?: HostItemResolvers.Resolvers; - CloudFields?: CloudFieldsResolvers.Resolvers; - CloudInstance?: CloudInstanceResolvers.Resolvers; - CloudMachine?: CloudMachineResolvers.Resolvers; - FirstLastSeenHost?: FirstLastSeenHostResolvers.Resolvers; - IpOverviewData?: IpOverviewDataResolvers.Resolvers; - Overview?: OverviewResolvers.Resolvers; - AutonomousSystem?: AutonomousSystemResolvers.Resolvers; - AutonomousSystemOrganization?: AutonomousSystemOrganizationResolvers.Resolvers; - UsersData?: UsersDataResolvers.Resolvers; - UsersEdges?: UsersEdgesResolvers.Resolvers; - UsersNode?: UsersNodeResolvers.Resolvers; - UsersItem?: UsersItemResolvers.Resolvers; - KpiNetworkData?: KpiNetworkDataResolvers.Resolvers; - KpiNetworkHistogramData?: KpiNetworkHistogramDataResolvers.Resolvers; - KpiHostsData?: KpiHostsDataResolvers.Resolvers; - KpiHostHistogramData?: KpiHostHistogramDataResolvers.Resolvers; - KpiHostDetailsData?: KpiHostDetailsDataResolvers.Resolvers; - MatrixHistogramOverTimeData?: MatrixHistogramOverTimeDataResolvers.Resolvers; - MatrixOverTimeHistogramData?: MatrixOverTimeHistogramDataResolvers.Resolvers; - NetworkTopCountriesData?: NetworkTopCountriesDataResolvers.Resolvers; - NetworkTopCountriesEdges?: NetworkTopCountriesEdgesResolvers.Resolvers; - NetworkTopCountriesItem?: NetworkTopCountriesItemResolvers.Resolvers; - TopCountriesItemSource?: TopCountriesItemSourceResolvers.Resolvers; - GeoItem?: GeoItemResolvers.Resolvers; - TopCountriesItemDestination?: TopCountriesItemDestinationResolvers.Resolvers; - TopNetworkTablesEcsField?: TopNetworkTablesEcsFieldResolvers.Resolvers; - NetworkTopNFlowData?: NetworkTopNFlowDataResolvers.Resolvers; - NetworkTopNFlowEdges?: NetworkTopNFlowEdgesResolvers.Resolvers; - NetworkTopNFlowItem?: NetworkTopNFlowItemResolvers.Resolvers; - TopNFlowItemSource?: TopNFlowItemSourceResolvers.Resolvers; - AutonomousSystemItem?: AutonomousSystemItemResolvers.Resolvers; - TopNFlowItemDestination?: TopNFlowItemDestinationResolvers.Resolvers; - NetworkDnsData?: NetworkDnsDataResolvers.Resolvers; - NetworkDnsEdges?: NetworkDnsEdgesResolvers.Resolvers; - NetworkDnsItem?: NetworkDnsItemResolvers.Resolvers; - MatrixOverOrdinalHistogramData?: MatrixOverOrdinalHistogramDataResolvers.Resolvers; - NetworkDsOverTimeData?: NetworkDsOverTimeDataResolvers.Resolvers; - NetworkHttpData?: NetworkHttpDataResolvers.Resolvers; - NetworkHttpEdges?: NetworkHttpEdgesResolvers.Resolvers; - NetworkHttpItem?: NetworkHttpItemResolvers.Resolvers; - OverviewNetworkData?: OverviewNetworkDataResolvers.Resolvers; - OverviewHostData?: OverviewHostDataResolvers.Resolvers; - TlsData?: TlsDataResolvers.Resolvers; - TlsEdges?: TlsEdgesResolvers.Resolvers; - TlsNode?: TlsNodeResolvers.Resolvers; - UncommonProcessesData?: UncommonProcessesDataResolvers.Resolvers; - UncommonProcessesEdges?: UncommonProcessesEdgesResolvers.Resolvers; - UncommonProcessItem?: UncommonProcessItemResolvers.Resolvers; - SayMyName?: SayMyNameResolvers.Resolvers; - TimelineResult?: TimelineResultResolvers.Resolvers; - ColumnHeaderResult?: ColumnHeaderResultResolvers.Resolvers; - DataProviderResult?: DataProviderResultResolvers.Resolvers; - QueryMatchResult?: QueryMatchResultResolvers.Resolvers; - DateRangePickerResult?: DateRangePickerResultResolvers.Resolvers; - FavoriteTimelineResult?: FavoriteTimelineResultResolvers.Resolvers; - FilterTimelineResult?: FilterTimelineResultResolvers.Resolvers; - FilterMetaTimelineResult?: FilterMetaTimelineResultResolvers.Resolvers; - SerializedFilterQueryResult?: SerializedFilterQueryResultResolvers.Resolvers; - SerializedKueryQueryResult?: SerializedKueryQueryResultResolvers.Resolvers; - KueryFilterQueryResult?: KueryFilterQueryResultResolvers.Resolvers; - SortTimelineResult?: SortTimelineResultResolvers.Resolvers; - ResponseTimelines?: ResponseTimelinesResolvers.Resolvers; - Mutation?: MutationResolvers.Resolvers; - ResponseNote?: ResponseNoteResolvers.Resolvers; - ResponseTimeline?: ResponseTimelineResolvers.Resolvers; - ResponseFavoriteTimeline?: ResponseFavoriteTimelineResolvers.Resolvers; - EcsEdges?: EcsEdgesResolvers.Resolvers; - EventsTimelineData?: EventsTimelineDataResolvers.Resolvers; - OsFields?: OsFieldsResolvers.Resolvers; - HostFields?: HostFieldsResolvers.Resolvers; - ToStringArray?: GraphQLScalarType; - Date?: GraphQLScalarType; - ToNumberArray?: GraphQLScalarType; - ToDateArray?: GraphQLScalarType; - ToBooleanArray?: GraphQLScalarType; - ToAny?: GraphQLScalarType; - EsValue?: GraphQLScalarType; -} & { [typeName: string]: never }; - -export type IDirectiveResolvers = { - skip?: SkipDirectiveResolver; - include?: IncludeDirectiveResolver; - deprecated?: DeprecatedDirectiveResolver; -} & { [directiveName: string]: never }; +/** Mapping between all available schema types and the resolvers types */ +export type ResolversTypes = ResolversObject<{ + Query: ResolverTypeWrapper<{}>, + ID: ResolverTypeWrapper, + NoteResult: ResolverTypeWrapper, + String: ResolverTypeWrapper, + Float: ResolverTypeWrapper, + PageInfoNote: PageInfoNote, + SortNote: SortNote, + SortFieldNote: SortFieldNote, + Direction: Direction, + ResponseNotes: ResolverTypeWrapper, + PinnedEvent: ResolverTypeWrapper, + Source: ResolverTypeWrapper, + SourceConfiguration: ResolverTypeWrapper, + SourceFields: ResolverTypeWrapper, + SourceStatus: ResolverTypeWrapper, + Boolean: ResolverTypeWrapper, + IndexField: ResolverTypeWrapper, + TimerangeInput: TimerangeInput, + PaginationInputPaginated: PaginationInputPaginated, + AuthenticationsData: ResolverTypeWrapper, + AuthenticationsEdges: ResolverTypeWrapper, + AuthenticationItem: ResolverTypeWrapper, + UserEcsFields: ResolverTypeWrapper, + ToStringArray: ResolverTypeWrapper, + LastSourceHost: ResolverTypeWrapper, + Date: ResolverTypeWrapper, + SourceEcsFields: ResolverTypeWrapper, + ToNumberArray: ResolverTypeWrapper, + GeoEcsFields: ResolverTypeWrapper, + Location: ResolverTypeWrapper, + HostEcsFields: ResolverTypeWrapper, + OsEcsFields: ResolverTypeWrapper, + CursorType: ResolverTypeWrapper, + PageInfoPaginated: ResolverTypeWrapper, + Inspect: ResolverTypeWrapper, + PaginationInput: PaginationInput, + SortField: SortField, + TimelineData: ResolverTypeWrapper, + TimelineEdges: ResolverTypeWrapper, + TimelineItem: ResolverTypeWrapper, + TimelineNonEcsData: ResolverTypeWrapper, + ECS: ResolverTypeWrapper, + AuditdEcsFields: ResolverTypeWrapper, + AuditdData: ResolverTypeWrapper, + Summary: ResolverTypeWrapper, + PrimarySecondary: ResolverTypeWrapper, + DestinationEcsFields: ResolverTypeWrapper, + DnsEcsFields: ResolverTypeWrapper, + DnsQuestionData: ResolverTypeWrapper, + EndgameEcsFields: ResolverTypeWrapper, + EventEcsFields: ResolverTypeWrapper, + ToDateArray: ResolverTypeWrapper, + NetworkEcsField: ResolverTypeWrapper, + RuleEcsField: ResolverTypeWrapper, + SignalField: ResolverTypeWrapper, + RuleField: ResolverTypeWrapper, + ToBooleanArray: ResolverTypeWrapper, + ToAny: ResolverTypeWrapper, + SuricataEcsFields: ResolverTypeWrapper, + SuricataEveData: ResolverTypeWrapper, + SuricataAlertData: ResolverTypeWrapper, + TlsEcsFields: ResolverTypeWrapper, + TlsClientCertificateData: ResolverTypeWrapper, + FingerprintData: ResolverTypeWrapper, + TlsFingerprintsData: ResolverTypeWrapper, + TlsJa3Data: ResolverTypeWrapper, + TlsServerCertificateData: ResolverTypeWrapper, + ZeekEcsFields: ResolverTypeWrapper, + ZeekConnectionData: ResolverTypeWrapper, + ZeekNoticeData: ResolverTypeWrapper, + ZeekDnsData: ResolverTypeWrapper, + ZeekHttpData: ResolverTypeWrapper, + ZeekFileData: ResolverTypeWrapper, + ZeekSslData: ResolverTypeWrapper, + HttpEcsFields: ResolverTypeWrapper, + HttpRequestData: ResolverTypeWrapper, + HttpBodyData: ResolverTypeWrapper, + HttpResponseData: ResolverTypeWrapper, + UrlEcsFields: ResolverTypeWrapper, + WinlogEcsFields: ResolverTypeWrapper, + ProcessEcsFields: ResolverTypeWrapper, + ProcessHashData: ResolverTypeWrapper, + Thread: ResolverTypeWrapper, + FileFields: ResolverTypeWrapper, + SystemEcsField: ResolverTypeWrapper, + AuditEcsFields: ResolverTypeWrapper, + PackageEcsFields: ResolverTypeWrapper, + AuthEcsFields: ResolverTypeWrapper, + SshEcsFields: ResolverTypeWrapper, + PageInfo: ResolverTypeWrapper, + TimelineDetailsData: ResolverTypeWrapper, + DetailItem: ResolverTypeWrapper, + EsValue: ResolverTypeWrapper, + LastEventIndexKey: LastEventIndexKey, + LastTimeDetails: LastTimeDetails, + LastEventTimeData: ResolverTypeWrapper, + HostsSortField: HostsSortField, + HostsFields: HostsFields, + HostsData: ResolverTypeWrapper, + HostsEdges: ResolverTypeWrapper, + HostItem: ResolverTypeWrapper, + CloudFields: ResolverTypeWrapper, + CloudInstance: ResolverTypeWrapper, + CloudMachine: ResolverTypeWrapper, + FirstLastSeenHost: ResolverTypeWrapper, + IpOverviewData: ResolverTypeWrapper, + Overview: ResolverTypeWrapper, + AutonomousSystem: ResolverTypeWrapper, + AutonomousSystemOrganization: ResolverTypeWrapper, + UsersSortField: UsersSortField, + UsersFields: UsersFields, + FlowTarget: FlowTarget, + UsersData: ResolverTypeWrapper, + UsersEdges: ResolverTypeWrapper, + UsersNode: ResolverTypeWrapper, + UsersItem: ResolverTypeWrapper, + KpiNetworkData: ResolverTypeWrapper, + KpiNetworkHistogramData: ResolverTypeWrapper, + KpiHostsData: ResolverTypeWrapper, + KpiHostHistogramData: ResolverTypeWrapper, + KpiHostDetailsData: ResolverTypeWrapper, + HistogramType: HistogramType, + MatrixHistogramOverTimeData: ResolverTypeWrapper, + MatrixOverTimeHistogramData: ResolverTypeWrapper, + FlowTargetSourceDest: FlowTargetSourceDest, + NetworkTopTablesSortField: NetworkTopTablesSortField, + NetworkTopTablesFields: NetworkTopTablesFields, + NetworkTopCountriesData: ResolverTypeWrapper, + NetworkTopCountriesEdges: ResolverTypeWrapper, + NetworkTopCountriesItem: ResolverTypeWrapper, + TopCountriesItemSource: ResolverTypeWrapper, + GeoItem: ResolverTypeWrapper, + TopCountriesItemDestination: ResolverTypeWrapper, + TopNetworkTablesEcsField: ResolverTypeWrapper, + NetworkTopNFlowData: ResolverTypeWrapper, + NetworkTopNFlowEdges: ResolverTypeWrapper, + NetworkTopNFlowItem: ResolverTypeWrapper, + TopNFlowItemSource: ResolverTypeWrapper, + AutonomousSystemItem: ResolverTypeWrapper, + TopNFlowItemDestination: ResolverTypeWrapper, + NetworkDnsSortField: NetworkDnsSortField, + NetworkDnsFields: NetworkDnsFields, + NetworkDnsData: ResolverTypeWrapper, + NetworkDnsEdges: ResolverTypeWrapper, + NetworkDnsItem: ResolverTypeWrapper, + MatrixOverOrdinalHistogramData: ResolverTypeWrapper, + NetworkDsOverTimeData: ResolverTypeWrapper, + NetworkHttpSortField: NetworkHttpSortField, + NetworkHttpData: ResolverTypeWrapper, + NetworkHttpEdges: ResolverTypeWrapper, + NetworkHttpItem: ResolverTypeWrapper, + OverviewNetworkData: ResolverTypeWrapper, + OverviewHostData: ResolverTypeWrapper, + TlsSortField: TlsSortField, + TlsFields: TlsFields, + TlsData: ResolverTypeWrapper, + TlsEdges: ResolverTypeWrapper, + TlsNode: ResolverTypeWrapper, + UncommonProcessesData: ResolverTypeWrapper, + UncommonProcessesEdges: ResolverTypeWrapper, + UncommonProcessItem: ResolverTypeWrapper, + SayMyName: ResolverTypeWrapper, + TimelineResult: ResolverTypeWrapper, + ColumnHeaderResult: ResolverTypeWrapper, + DataProviderResult: ResolverTypeWrapper, + QueryMatchResult: ResolverTypeWrapper, + DateRangePickerResult: ResolverTypeWrapper, + FavoriteTimelineResult: ResolverTypeWrapper, + FilterTimelineResult: ResolverTypeWrapper, + FilterMetaTimelineResult: ResolverTypeWrapper, + SerializedFilterQueryResult: ResolverTypeWrapper, + SerializedKueryQueryResult: ResolverTypeWrapper, + KueryFilterQueryResult: ResolverTypeWrapper, + SortTimelineResult: ResolverTypeWrapper, + PageInfoTimeline: PageInfoTimeline, + SortTimeline: SortTimeline, + SortFieldTimeline: SortFieldTimeline, + ResponseTimelines: ResolverTypeWrapper, + Mutation: ResolverTypeWrapper<{}>, + NoteInput: NoteInput, + ResponseNote: ResolverTypeWrapper, + TimelineInput: TimelineInput, + ColumnHeaderInput: ColumnHeaderInput, + DataProviderInput: DataProviderInput, + QueryMatchInput: QueryMatchInput, + FilterTimelineInput: FilterTimelineInput, + FilterMetaTimelineInput: FilterMetaTimelineInput, + SerializedFilterQueryInput: SerializedFilterQueryInput, + SerializedKueryQueryInput: SerializedKueryQueryInput, + KueryFilterQueryInput: KueryFilterQueryInput, + DateRangePickerInput: DateRangePickerInput, + SortTimelineInput: SortTimelineInput, + ResponseTimeline: ResolverTypeWrapper, + ResponseFavoriteTimeline: ResolverTypeWrapper, + EcsEdges: ResolverTypeWrapper, + EventsTimelineData: ResolverTypeWrapper, + FavoriteTimelineInput: FavoriteTimelineInput, + FlowDirection: FlowDirection, + HostFields: ResolverTypeWrapper, + OsFields: ResolverTypeWrapper, + NetworkDirectionEcs: NetworkDirectionEcs, + NetworkHttpFields: NetworkHttpFields, +}>; + +/** Mapping between all available schema types and the resolvers parents */ +export type ResolversParentTypes = ResolversObject<{ + Query: {}, + ID: Scalars['ID'], + NoteResult: NoteResult, + String: Scalars['String'], + Float: Scalars['Float'], + PageInfoNote: PageInfoNote, + SortNote: SortNote, + SortFieldNote: SortFieldNote, + Direction: Direction, + ResponseNotes: ResponseNotes, + PinnedEvent: PinnedEvent, + Source: Source, + SourceConfiguration: SourceConfiguration, + SourceFields: SourceFields, + SourceStatus: SourceStatus, + Boolean: Scalars['Boolean'], + IndexField: IndexField, + TimerangeInput: TimerangeInput, + PaginationInputPaginated: PaginationInputPaginated, + AuthenticationsData: AuthenticationsData, + AuthenticationsEdges: AuthenticationsEdges, + AuthenticationItem: AuthenticationItem, + UserEcsFields: UserEcsFields, + ToStringArray: Scalars['ToStringArray'], + LastSourceHost: LastSourceHost, + Date: Scalars['Date'], + SourceEcsFields: SourceEcsFields, + ToNumberArray: Scalars['ToNumberArray'], + GeoEcsFields: GeoEcsFields, + Location: Location, + HostEcsFields: HostEcsFields, + OsEcsFields: OsEcsFields, + CursorType: CursorType, + PageInfoPaginated: PageInfoPaginated, + Inspect: Inspect, + PaginationInput: PaginationInput, + SortField: SortField, + TimelineData: TimelineData, + TimelineEdges: TimelineEdges, + TimelineItem: TimelineItem, + TimelineNonEcsData: TimelineNonEcsData, + ECS: Ecs, + AuditdEcsFields: AuditdEcsFields, + AuditdData: AuditdData, + Summary: Summary, + PrimarySecondary: PrimarySecondary, + DestinationEcsFields: DestinationEcsFields, + DnsEcsFields: DnsEcsFields, + DnsQuestionData: DnsQuestionData, + EndgameEcsFields: EndgameEcsFields, + EventEcsFields: EventEcsFields, + ToDateArray: Scalars['ToDateArray'], + NetworkEcsField: NetworkEcsField, + RuleEcsField: RuleEcsField, + SignalField: SignalField, + RuleField: RuleField, + ToBooleanArray: Scalars['ToBooleanArray'], + ToAny: Scalars['ToAny'], + SuricataEcsFields: SuricataEcsFields, + SuricataEveData: SuricataEveData, + SuricataAlertData: SuricataAlertData, + TlsEcsFields: TlsEcsFields, + TlsClientCertificateData: TlsClientCertificateData, + FingerprintData: FingerprintData, + TlsFingerprintsData: TlsFingerprintsData, + TlsJa3Data: TlsJa3Data, + TlsServerCertificateData: TlsServerCertificateData, + ZeekEcsFields: ZeekEcsFields, + ZeekConnectionData: ZeekConnectionData, + ZeekNoticeData: ZeekNoticeData, + ZeekDnsData: ZeekDnsData, + ZeekHttpData: ZeekHttpData, + ZeekFileData: ZeekFileData, + ZeekSslData: ZeekSslData, + HttpEcsFields: HttpEcsFields, + HttpRequestData: HttpRequestData, + HttpBodyData: HttpBodyData, + HttpResponseData: HttpResponseData, + UrlEcsFields: UrlEcsFields, + WinlogEcsFields: WinlogEcsFields, + ProcessEcsFields: ProcessEcsFields, + ProcessHashData: ProcessHashData, + Thread: Thread, + FileFields: FileFields, + SystemEcsField: SystemEcsField, + AuditEcsFields: AuditEcsFields, + PackageEcsFields: PackageEcsFields, + AuthEcsFields: AuthEcsFields, + SshEcsFields: SshEcsFields, + PageInfo: PageInfo, + TimelineDetailsData: TimelineDetailsData, + DetailItem: DetailItem, + EsValue: Scalars['EsValue'], + LastEventIndexKey: LastEventIndexKey, + LastTimeDetails: LastTimeDetails, + LastEventTimeData: LastEventTimeData, + HostsSortField: HostsSortField, + HostsFields: HostsFields, + HostsData: HostsData, + HostsEdges: HostsEdges, + HostItem: HostItem, + CloudFields: CloudFields, + CloudInstance: CloudInstance, + CloudMachine: CloudMachine, + FirstLastSeenHost: FirstLastSeenHost, + IpOverviewData: IpOverviewData, + Overview: Overview, + AutonomousSystem: AutonomousSystem, + AutonomousSystemOrganization: AutonomousSystemOrganization, + UsersSortField: UsersSortField, + UsersFields: UsersFields, + FlowTarget: FlowTarget, + UsersData: UsersData, + UsersEdges: UsersEdges, + UsersNode: UsersNode, + UsersItem: UsersItem, + KpiNetworkData: KpiNetworkData, + KpiNetworkHistogramData: KpiNetworkHistogramData, + KpiHostsData: KpiHostsData, + KpiHostHistogramData: KpiHostHistogramData, + KpiHostDetailsData: KpiHostDetailsData, + HistogramType: HistogramType, + MatrixHistogramOverTimeData: MatrixHistogramOverTimeData, + MatrixOverTimeHistogramData: MatrixOverTimeHistogramData, + FlowTargetSourceDest: FlowTargetSourceDest, + NetworkTopTablesSortField: NetworkTopTablesSortField, + NetworkTopTablesFields: NetworkTopTablesFields, + NetworkTopCountriesData: NetworkTopCountriesData, + NetworkTopCountriesEdges: NetworkTopCountriesEdges, + NetworkTopCountriesItem: NetworkTopCountriesItem, + TopCountriesItemSource: TopCountriesItemSource, + GeoItem: GeoItem, + TopCountriesItemDestination: TopCountriesItemDestination, + TopNetworkTablesEcsField: TopNetworkTablesEcsField, + NetworkTopNFlowData: NetworkTopNFlowData, + NetworkTopNFlowEdges: NetworkTopNFlowEdges, + NetworkTopNFlowItem: NetworkTopNFlowItem, + TopNFlowItemSource: TopNFlowItemSource, + AutonomousSystemItem: AutonomousSystemItem, + TopNFlowItemDestination: TopNFlowItemDestination, + NetworkDnsSortField: NetworkDnsSortField, + NetworkDnsFields: NetworkDnsFields, + NetworkDnsData: NetworkDnsData, + NetworkDnsEdges: NetworkDnsEdges, + NetworkDnsItem: NetworkDnsItem, + MatrixOverOrdinalHistogramData: MatrixOverOrdinalHistogramData, + NetworkDsOverTimeData: NetworkDsOverTimeData, + NetworkHttpSortField: NetworkHttpSortField, + NetworkHttpData: NetworkHttpData, + NetworkHttpEdges: NetworkHttpEdges, + NetworkHttpItem: NetworkHttpItem, + OverviewNetworkData: OverviewNetworkData, + OverviewHostData: OverviewHostData, + TlsSortField: TlsSortField, + TlsFields: TlsFields, + TlsData: TlsData, + TlsEdges: TlsEdges, + TlsNode: TlsNode, + UncommonProcessesData: UncommonProcessesData, + UncommonProcessesEdges: UncommonProcessesEdges, + UncommonProcessItem: UncommonProcessItem, + SayMyName: SayMyName, + TimelineResult: TimelineResult, + ColumnHeaderResult: ColumnHeaderResult, + DataProviderResult: DataProviderResult, + QueryMatchResult: QueryMatchResult, + DateRangePickerResult: DateRangePickerResult, + FavoriteTimelineResult: FavoriteTimelineResult, + FilterTimelineResult: FilterTimelineResult, + FilterMetaTimelineResult: FilterMetaTimelineResult, + SerializedFilterQueryResult: SerializedFilterQueryResult, + SerializedKueryQueryResult: SerializedKueryQueryResult, + KueryFilterQueryResult: KueryFilterQueryResult, + SortTimelineResult: SortTimelineResult, + PageInfoTimeline: PageInfoTimeline, + SortTimeline: SortTimeline, + SortFieldTimeline: SortFieldTimeline, + ResponseTimelines: ResponseTimelines, + Mutation: {}, + NoteInput: NoteInput, + ResponseNote: ResponseNote, + TimelineInput: TimelineInput, + ColumnHeaderInput: ColumnHeaderInput, + DataProviderInput: DataProviderInput, + QueryMatchInput: QueryMatchInput, + FilterTimelineInput: FilterTimelineInput, + FilterMetaTimelineInput: FilterMetaTimelineInput, + SerializedFilterQueryInput: SerializedFilterQueryInput, + SerializedKueryQueryInput: SerializedKueryQueryInput, + KueryFilterQueryInput: KueryFilterQueryInput, + DateRangePickerInput: DateRangePickerInput, + SortTimelineInput: SortTimelineInput, + ResponseTimeline: ResponseTimeline, + ResponseFavoriteTimeline: ResponseFavoriteTimeline, + EcsEdges: EcsEdges, + EventsTimelineData: EventsTimelineData, + FavoriteTimelineInput: FavoriteTimelineInput, + FlowDirection: FlowDirection, + HostFields: HostFields, + OsFields: OsFields, + NetworkDirectionEcs: NetworkDirectionEcs, + NetworkHttpFields: NetworkHttpFields, +}>; + +export type AuditdDataResolvers = ResolversObject<{ + acct?: Resolver, ParentType, ContextType>, + terminal?: Resolver, ParentType, ContextType>, + op?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type AuditdEcsFieldsResolvers = ResolversObject<{ + result?: Resolver, ParentType, ContextType>, + session?: Resolver, ParentType, ContextType>, + data?: Resolver, ParentType, ContextType>, + summary?: Resolver, ParentType, ContextType>, + sequence?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type AuditEcsFieldsResolvers = ResolversObject<{ + package?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type AuthEcsFieldsResolvers = ResolversObject<{ + ssh?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type AuthenticationItemResolvers = ResolversObject<{ + _id?: Resolver, + failures?: Resolver, + successes?: Resolver, + user?: Resolver, + lastSuccess?: Resolver, ParentType, ContextType>, + lastFailure?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type AuthenticationsDataResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + pageInfo?: Resolver, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type AuthenticationsEdgesResolvers = ResolversObject<{ + node?: Resolver, + cursor?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type AutonomousSystemResolvers = ResolversObject<{ + number?: Resolver, ParentType, ContextType>, + organization?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type AutonomousSystemItemResolvers = ResolversObject<{ + name?: Resolver, ParentType, ContextType>, + number?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type AutonomousSystemOrganizationResolvers = ResolversObject<{ + name?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type CloudFieldsResolvers = ResolversObject<{ + instance?: Resolver, ParentType, ContextType>, + machine?: Resolver, ParentType, ContextType>, + provider?: Resolver>>, ParentType, ContextType>, + region?: Resolver>>, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type CloudInstanceResolvers = ResolversObject<{ + id?: Resolver>>, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type CloudMachineResolvers = ResolversObject<{ + type?: Resolver>>, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ColumnHeaderResultResolvers = ResolversObject<{ + aggregatable?: Resolver, ParentType, ContextType>, + category?: Resolver, ParentType, ContextType>, + columnHeaderType?: Resolver, ParentType, ContextType>, + description?: Resolver, ParentType, ContextType>, + example?: Resolver, ParentType, ContextType>, + indexes?: Resolver>, ParentType, ContextType>, + id?: Resolver, ParentType, ContextType>, + name?: Resolver, ParentType, ContextType>, + placeholder?: Resolver, ParentType, ContextType>, + searchable?: Resolver, ParentType, ContextType>, + type?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type CursorTypeResolvers = ResolversObject<{ + value?: Resolver, ParentType, ContextType>, + tiebreaker?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type DataProviderResultResolvers = ResolversObject<{ + id?: Resolver, ParentType, ContextType>, + name?: Resolver, ParentType, ContextType>, + enabled?: Resolver, ParentType, ContextType>, + excluded?: Resolver, ParentType, ContextType>, + kqlQuery?: Resolver, ParentType, ContextType>, + queryMatch?: Resolver, ParentType, ContextType>, + and?: Resolver>, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export interface DateScalarConfig extends GraphQLScalarTypeConfig { + name: 'Date' +} + +export type DateRangePickerResultResolvers = ResolversObject<{ + start?: Resolver, ParentType, ContextType>, + end?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type DestinationEcsFieldsResolvers = ResolversObject<{ + bytes?: Resolver, ParentType, ContextType>, + ip?: Resolver, ParentType, ContextType>, + port?: Resolver, ParentType, ContextType>, + domain?: Resolver, ParentType, ContextType>, + geo?: Resolver, ParentType, ContextType>, + packets?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type DetailItemResolvers = ResolversObject<{ + field?: Resolver, + values?: Resolver, ParentType, ContextType>, + originalValue?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type DnsEcsFieldsResolvers = ResolversObject<{ + question?: Resolver, ParentType, ContextType>, + resolved_ip?: Resolver, ParentType, ContextType>, + response_code?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type DnsQuestionDataResolvers = ResolversObject<{ + name?: Resolver, ParentType, ContextType>, + type?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type EcsResolvers = ResolversObject<{ + _id?: Resolver, + _index?: Resolver, ParentType, ContextType>, + auditd?: Resolver, ParentType, ContextType>, + destination?: Resolver, ParentType, ContextType>, + dns?: Resolver, ParentType, ContextType>, + endgame?: Resolver, ParentType, ContextType>, + event?: Resolver, ParentType, ContextType>, + geo?: Resolver, ParentType, ContextType>, + host?: Resolver, ParentType, ContextType>, + network?: Resolver, ParentType, ContextType>, + rule?: Resolver, ParentType, ContextType>, + signal?: Resolver, ParentType, ContextType>, + source?: Resolver, ParentType, ContextType>, + suricata?: Resolver, ParentType, ContextType>, + tls?: Resolver, ParentType, ContextType>, + zeek?: Resolver, ParentType, ContextType>, + http?: Resolver, ParentType, ContextType>, + url?: Resolver, ParentType, ContextType>, + timestamp?: Resolver, ParentType, ContextType>, + message?: Resolver, ParentType, ContextType>, + user?: Resolver, ParentType, ContextType>, + winlog?: Resolver, ParentType, ContextType>, + process?: Resolver, ParentType, ContextType>, + file?: Resolver, ParentType, ContextType>, + system?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type EcsEdgesResolvers = ResolversObject<{ + node?: Resolver, + cursor?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type EndgameEcsFieldsResolvers = ResolversObject<{ + exit_code?: Resolver, ParentType, ContextType>, + file_name?: Resolver, ParentType, ContextType>, + file_path?: Resolver, ParentType, ContextType>, + logon_type?: Resolver, ParentType, ContextType>, + parent_process_name?: Resolver, ParentType, ContextType>, + pid?: Resolver, ParentType, ContextType>, + process_name?: Resolver, ParentType, ContextType>, + subject_domain_name?: Resolver, ParentType, ContextType>, + subject_logon_id?: Resolver, ParentType, ContextType>, + subject_user_name?: Resolver, ParentType, ContextType>, + target_domain_name?: Resolver, ParentType, ContextType>, + target_logon_id?: Resolver, ParentType, ContextType>, + target_user_name?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export interface EsValueScalarConfig extends GraphQLScalarTypeConfig { + name: 'EsValue' +} + +export type EventEcsFieldsResolvers = ResolversObject<{ + action?: Resolver, ParentType, ContextType>, + category?: Resolver, ParentType, ContextType>, + code?: Resolver, ParentType, ContextType>, + created?: Resolver, ParentType, ContextType>, + dataset?: Resolver, ParentType, ContextType>, + duration?: Resolver, ParentType, ContextType>, + end?: Resolver, ParentType, ContextType>, + hash?: Resolver, ParentType, ContextType>, + id?: Resolver, ParentType, ContextType>, + kind?: Resolver, ParentType, ContextType>, + module?: Resolver, ParentType, ContextType>, + original?: Resolver, ParentType, ContextType>, + outcome?: Resolver, ParentType, ContextType>, + risk_score?: Resolver, ParentType, ContextType>, + risk_score_norm?: Resolver, ParentType, ContextType>, + severity?: Resolver, ParentType, ContextType>, + start?: Resolver, ParentType, ContextType>, + timezone?: Resolver, ParentType, ContextType>, + type?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type EventsTimelineDataResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + pageInfo?: Resolver, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type FavoriteTimelineResultResolvers = ResolversObject<{ + fullName?: Resolver, ParentType, ContextType>, + userName?: Resolver, ParentType, ContextType>, + favoriteDate?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type FileFieldsResolvers = ResolversObject<{ + name?: Resolver, ParentType, ContextType>, + path?: Resolver, ParentType, ContextType>, + target_path?: Resolver, ParentType, ContextType>, + extension?: Resolver, ParentType, ContextType>, + type?: Resolver, ParentType, ContextType>, + device?: Resolver, ParentType, ContextType>, + inode?: Resolver, ParentType, ContextType>, + uid?: Resolver, ParentType, ContextType>, + owner?: Resolver, ParentType, ContextType>, + gid?: Resolver, ParentType, ContextType>, + group?: Resolver, ParentType, ContextType>, + mode?: Resolver, ParentType, ContextType>, + size?: Resolver, ParentType, ContextType>, + mtime?: Resolver, ParentType, ContextType>, + ctime?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type FilterMetaTimelineResultResolvers = ResolversObject<{ + alias?: Resolver, ParentType, ContextType>, + controlledBy?: Resolver, ParentType, ContextType>, + disabled?: Resolver, ParentType, ContextType>, + field?: Resolver, ParentType, ContextType>, + formattedValue?: Resolver, ParentType, ContextType>, + index?: Resolver, ParentType, ContextType>, + key?: Resolver, ParentType, ContextType>, + negate?: Resolver, ParentType, ContextType>, + params?: Resolver, ParentType, ContextType>, + type?: Resolver, ParentType, ContextType>, + value?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type FilterTimelineResultResolvers = ResolversObject<{ + exists?: Resolver, ParentType, ContextType>, + meta?: Resolver, ParentType, ContextType>, + match_all?: Resolver, ParentType, ContextType>, + missing?: Resolver, ParentType, ContextType>, + query?: Resolver, ParentType, ContextType>, + range?: Resolver, ParentType, ContextType>, + script?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type FingerprintDataResolvers = ResolversObject<{ + sha1?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type FirstLastSeenHostResolvers = ResolversObject<{ + inspect?: Resolver, ParentType, ContextType>, + firstSeen?: Resolver, ParentType, ContextType>, + lastSeen?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type GeoEcsFieldsResolvers = ResolversObject<{ + city_name?: Resolver, ParentType, ContextType>, + continent_name?: Resolver, ParentType, ContextType>, + country_iso_code?: Resolver, ParentType, ContextType>, + country_name?: Resolver, ParentType, ContextType>, + location?: Resolver, ParentType, ContextType>, + region_iso_code?: Resolver, ParentType, ContextType>, + region_name?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type GeoItemResolvers = ResolversObject<{ + geo?: Resolver, ParentType, ContextType>, + flowTarget?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type HostEcsFieldsResolvers = ResolversObject<{ + architecture?: Resolver, ParentType, ContextType>, + id?: Resolver, ParentType, ContextType>, + ip?: Resolver, ParentType, ContextType>, + mac?: Resolver, ParentType, ContextType>, + name?: Resolver, ParentType, ContextType>, + os?: Resolver, ParentType, ContextType>, + type?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type HostFieldsResolvers = ResolversObject<{ + architecture?: Resolver, ParentType, ContextType>, + id?: Resolver, ParentType, ContextType>, + ip?: Resolver>>, ParentType, ContextType>, + mac?: Resolver>>, ParentType, ContextType>, + name?: Resolver, ParentType, ContextType>, + os?: Resolver, ParentType, ContextType>, + type?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type HostItemResolvers = ResolversObject<{ + _id?: Resolver, ParentType, ContextType>, + lastSeen?: Resolver, ParentType, ContextType>, + host?: Resolver, ParentType, ContextType>, + cloud?: Resolver, ParentType, ContextType>, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type HostsDataResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + pageInfo?: Resolver, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type HostsEdgesResolvers = ResolversObject<{ + node?: Resolver, + cursor?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type HttpBodyDataResolvers = ResolversObject<{ + content?: Resolver, ParentType, ContextType>, + bytes?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type HttpEcsFieldsResolvers = ResolversObject<{ + version?: Resolver, ParentType, ContextType>, + request?: Resolver, ParentType, ContextType>, + response?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type HttpRequestDataResolvers = ResolversObject<{ + method?: Resolver, ParentType, ContextType>, + body?: Resolver, ParentType, ContextType>, + referrer?: Resolver, ParentType, ContextType>, + bytes?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type HttpResponseDataResolvers = ResolversObject<{ + status_code?: Resolver, ParentType, ContextType>, + body?: Resolver, ParentType, ContextType>, + bytes?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type IndexFieldResolvers = ResolversObject<{ + category?: Resolver, + example?: Resolver, ParentType, ContextType>, + indexes?: Resolver>, ParentType, ContextType>, + name?: Resolver, + type?: Resolver, + searchable?: Resolver, + aggregatable?: Resolver, + description?: Resolver, ParentType, ContextType>, + format?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type InspectResolvers = ResolversObject<{ + dsl?: Resolver, ParentType, ContextType>, + response?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type IpOverviewDataResolvers = ResolversObject<{ + client?: Resolver, ParentType, ContextType>, + destination?: Resolver, ParentType, ContextType>, + host?: Resolver, + server?: Resolver, ParentType, ContextType>, + source?: Resolver, ParentType, ContextType>, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type KpiHostDetailsDataResolvers = ResolversObject<{ + authSuccess?: Resolver, ParentType, ContextType>, + authSuccessHistogram?: Resolver>, ParentType, ContextType>, + authFailure?: Resolver, ParentType, ContextType>, + authFailureHistogram?: Resolver>, ParentType, ContextType>, + uniqueSourceIps?: Resolver, ParentType, ContextType>, + uniqueSourceIpsHistogram?: Resolver>, ParentType, ContextType>, + uniqueDestinationIps?: Resolver, ParentType, ContextType>, + uniqueDestinationIpsHistogram?: Resolver>, ParentType, ContextType>, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type KpiHostHistogramDataResolvers = ResolversObject<{ + x?: Resolver, ParentType, ContextType>, + y?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type KpiHostsDataResolvers = ResolversObject<{ + hosts?: Resolver, ParentType, ContextType>, + hostsHistogram?: Resolver>, ParentType, ContextType>, + authSuccess?: Resolver, ParentType, ContextType>, + authSuccessHistogram?: Resolver>, ParentType, ContextType>, + authFailure?: Resolver, ParentType, ContextType>, + authFailureHistogram?: Resolver>, ParentType, ContextType>, + uniqueSourceIps?: Resolver, ParentType, ContextType>, + uniqueSourceIpsHistogram?: Resolver>, ParentType, ContextType>, + uniqueDestinationIps?: Resolver, ParentType, ContextType>, + uniqueDestinationIpsHistogram?: Resolver>, ParentType, ContextType>, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type KpiNetworkDataResolvers = ResolversObject<{ + networkEvents?: Resolver, ParentType, ContextType>, + uniqueFlowId?: Resolver, ParentType, ContextType>, + uniqueSourcePrivateIps?: Resolver, ParentType, ContextType>, + uniqueSourcePrivateIpsHistogram?: Resolver>, ParentType, ContextType>, + uniqueDestinationPrivateIps?: Resolver, ParentType, ContextType>, + uniqueDestinationPrivateIpsHistogram?: Resolver>, ParentType, ContextType>, + dnsQueries?: Resolver, ParentType, ContextType>, + tlsHandshakes?: Resolver, ParentType, ContextType>, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type KpiNetworkHistogramDataResolvers = ResolversObject<{ + x?: Resolver, ParentType, ContextType>, + y?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type KueryFilterQueryResultResolvers = ResolversObject<{ + kind?: Resolver, ParentType, ContextType>, + expression?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type LastEventTimeDataResolvers = ResolversObject<{ + lastSeen?: Resolver, ParentType, ContextType>, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type LastSourceHostResolvers = ResolversObject<{ + timestamp?: Resolver, ParentType, ContextType>, + source?: Resolver, ParentType, ContextType>, + host?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type LocationResolvers = ResolversObject<{ + lon?: Resolver, ParentType, ContextType>, + lat?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type MatrixHistogramOverTimeDataResolvers = ResolversObject<{ + inspect?: Resolver, ParentType, ContextType>, + matrixHistogramData?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type MatrixOverOrdinalHistogramDataResolvers = ResolversObject<{ + x?: Resolver, + y?: Resolver, + g?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type MatrixOverTimeHistogramDataResolvers = ResolversObject<{ + x?: Resolver, ParentType, ContextType>, + y?: Resolver, ParentType, ContextType>, + g?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type MutationResolvers = ResolversObject<{ + persistNote?: Resolver>, + deleteNote?: Resolver, ParentType, ContextType, RequireFields>, + deleteNoteByTimelineId?: Resolver, ParentType, ContextType, RequireFields>, + persistPinnedEventOnTimeline?: Resolver, ParentType, ContextType, RequireFields>, + deletePinnedEventOnTimeline?: Resolver>, + deleteAllPinnedEventsOnTimeline?: Resolver>, + persistTimeline?: Resolver>, + persistFavorite?: Resolver, + deleteTimeline?: Resolver>, +}>; + +export type NetworkDnsDataResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + pageInfo?: Resolver, + inspect?: Resolver, ParentType, ContextType>, + histogram?: Resolver>, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkDnsEdgesResolvers = ResolversObject<{ + node?: Resolver, + cursor?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkDnsItemResolvers = ResolversObject<{ + _id?: Resolver, ParentType, ContextType>, + dnsBytesIn?: Resolver, ParentType, ContextType>, + dnsBytesOut?: Resolver, ParentType, ContextType>, + dnsName?: Resolver, ParentType, ContextType>, + queryCount?: Resolver, ParentType, ContextType>, + uniqueDomains?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkDsOverTimeDataResolvers = ResolversObject<{ + inspect?: Resolver, ParentType, ContextType>, + matrixHistogramData?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkEcsFieldResolvers = ResolversObject<{ + bytes?: Resolver, ParentType, ContextType>, + community_id?: Resolver, ParentType, ContextType>, + direction?: Resolver, ParentType, ContextType>, + packets?: Resolver, ParentType, ContextType>, + protocol?: Resolver, ParentType, ContextType>, + transport?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkHttpDataResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + pageInfo?: Resolver, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkHttpEdgesResolvers = ResolversObject<{ + node?: Resolver, + cursor?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkHttpItemResolvers = ResolversObject<{ + _id?: Resolver, ParentType, ContextType>, + domains?: Resolver, ParentType, ContextType>, + lastHost?: Resolver, ParentType, ContextType>, + lastSourceIp?: Resolver, ParentType, ContextType>, + methods?: Resolver, ParentType, ContextType>, + path?: Resolver, ParentType, ContextType>, + requestCount?: Resolver, ParentType, ContextType>, + statuses?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkTopCountriesDataResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + pageInfo?: Resolver, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkTopCountriesEdgesResolvers = ResolversObject<{ + node?: Resolver, + cursor?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkTopCountriesItemResolvers = ResolversObject<{ + _id?: Resolver, ParentType, ContextType>, + source?: Resolver, ParentType, ContextType>, + destination?: Resolver, ParentType, ContextType>, + network?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkTopNFlowDataResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + pageInfo?: Resolver, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkTopNFlowEdgesResolvers = ResolversObject<{ + node?: Resolver, + cursor?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NetworkTopNFlowItemResolvers = ResolversObject<{ + _id?: Resolver, ParentType, ContextType>, + source?: Resolver, ParentType, ContextType>, + destination?: Resolver, ParentType, ContextType>, + network?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type NoteResultResolvers = ResolversObject<{ + eventId?: Resolver, ParentType, ContextType>, + note?: Resolver, ParentType, ContextType>, + timelineId?: Resolver, ParentType, ContextType>, + noteId?: Resolver, + created?: Resolver, ParentType, ContextType>, + createdBy?: Resolver, ParentType, ContextType>, + timelineVersion?: Resolver, ParentType, ContextType>, + updated?: Resolver, ParentType, ContextType>, + updatedBy?: Resolver, ParentType, ContextType>, + version?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type OsEcsFieldsResolvers = ResolversObject<{ + platform?: Resolver, ParentType, ContextType>, + name?: Resolver, ParentType, ContextType>, + full?: Resolver, ParentType, ContextType>, + family?: Resolver, ParentType, ContextType>, + version?: Resolver, ParentType, ContextType>, + kernel?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type OsFieldsResolvers = ResolversObject<{ + platform?: Resolver, ParentType, ContextType>, + name?: Resolver, ParentType, ContextType>, + full?: Resolver, ParentType, ContextType>, + family?: Resolver, ParentType, ContextType>, + version?: Resolver, ParentType, ContextType>, + kernel?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type OverviewResolvers = ResolversObject<{ + firstSeen?: Resolver, ParentType, ContextType>, + lastSeen?: Resolver, ParentType, ContextType>, + autonomousSystem?: Resolver, + geo?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type OverviewHostDataResolvers = ResolversObject<{ + auditbeatAuditd?: Resolver, ParentType, ContextType>, + auditbeatFIM?: Resolver, ParentType, ContextType>, + auditbeatLogin?: Resolver, ParentType, ContextType>, + auditbeatPackage?: Resolver, ParentType, ContextType>, + auditbeatProcess?: Resolver, ParentType, ContextType>, + auditbeatUser?: Resolver, ParentType, ContextType>, + endgameDns?: Resolver, ParentType, ContextType>, + endgameFile?: Resolver, ParentType, ContextType>, + endgameImageLoad?: Resolver, ParentType, ContextType>, + endgameNetwork?: Resolver, ParentType, ContextType>, + endgameProcess?: Resolver, ParentType, ContextType>, + endgameRegistry?: Resolver, ParentType, ContextType>, + endgameSecurity?: Resolver, ParentType, ContextType>, + filebeatSystemModule?: Resolver, ParentType, ContextType>, + winlogbeatSecurity?: Resolver, ParentType, ContextType>, + winlogbeatMWSysmonOperational?: Resolver, ParentType, ContextType>, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type OverviewNetworkDataResolvers = ResolversObject<{ + auditbeatSocket?: Resolver, ParentType, ContextType>, + filebeatCisco?: Resolver, ParentType, ContextType>, + filebeatNetflow?: Resolver, ParentType, ContextType>, + filebeatPanw?: Resolver, ParentType, ContextType>, + filebeatSuricata?: Resolver, ParentType, ContextType>, + filebeatZeek?: Resolver, ParentType, ContextType>, + packetbeatDNS?: Resolver, ParentType, ContextType>, + packetbeatFlow?: Resolver, ParentType, ContextType>, + packetbeatTLS?: Resolver, ParentType, ContextType>, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type PackageEcsFieldsResolvers = ResolversObject<{ + arch?: Resolver, ParentType, ContextType>, + entity_id?: Resolver, ParentType, ContextType>, + name?: Resolver, ParentType, ContextType>, + size?: Resolver, ParentType, ContextType>, + summary?: Resolver, ParentType, ContextType>, + version?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type PageInfoResolvers = ResolversObject<{ + endCursor?: Resolver, ParentType, ContextType>, + hasNextPage?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type PageInfoPaginatedResolvers = ResolversObject<{ + activePage?: Resolver, + fakeTotalCount?: Resolver, + showMorePagesIndicator?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type PinnedEventResolvers = ResolversObject<{ + code?: Resolver, ParentType, ContextType>, + message?: Resolver, ParentType, ContextType>, + pinnedEventId?: Resolver, + eventId?: Resolver, ParentType, ContextType>, + timelineId?: Resolver, ParentType, ContextType>, + timelineVersion?: Resolver, ParentType, ContextType>, + created?: Resolver, ParentType, ContextType>, + createdBy?: Resolver, ParentType, ContextType>, + updated?: Resolver, ParentType, ContextType>, + updatedBy?: Resolver, ParentType, ContextType>, + version?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type PrimarySecondaryResolvers = ResolversObject<{ + primary?: Resolver, ParentType, ContextType>, + secondary?: Resolver, ParentType, ContextType>, + type?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ProcessEcsFieldsResolvers = ResolversObject<{ + hash?: Resolver, ParentType, ContextType>, + pid?: Resolver, ParentType, ContextType>, + name?: Resolver, ParentType, ContextType>, + ppid?: Resolver, ParentType, ContextType>, + args?: Resolver, ParentType, ContextType>, + executable?: Resolver, ParentType, ContextType>, + title?: Resolver, ParentType, ContextType>, + thread?: Resolver, ParentType, ContextType>, + working_directory?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ProcessHashDataResolvers = ResolversObject<{ + md5?: Resolver, ParentType, ContextType>, + sha1?: Resolver, ParentType, ContextType>, + sha256?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type QueryResolvers = ResolversObject<{ + getNote?: Resolver>, + getNotesByTimelineId?: Resolver, ParentType, ContextType, RequireFields>, + getNotesByEventId?: Resolver, ParentType, ContextType, RequireFields>, + getAllNotes?: Resolver, + getAllPinnedEventsByTimelineId?: Resolver, ParentType, ContextType, RequireFields>, + source?: Resolver>, + allSources?: Resolver, ParentType, ContextType>, + getOneTimeline?: Resolver>, + getAllTimeline?: Resolver, +}>; + +export type QueryMatchResultResolvers = ResolversObject<{ + field?: Resolver, ParentType, ContextType>, + displayField?: Resolver, ParentType, ContextType>, + value?: Resolver, ParentType, ContextType>, + displayValue?: Resolver, ParentType, ContextType>, + operator?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ResponseFavoriteTimelineResolvers = ResolversObject<{ + code?: Resolver, ParentType, ContextType>, + message?: Resolver, ParentType, ContextType>, + savedObjectId?: Resolver, + version?: Resolver, + favorite?: Resolver>, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ResponseNoteResolvers = ResolversObject<{ + code?: Resolver, ParentType, ContextType>, + message?: Resolver, ParentType, ContextType>, + note?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ResponseNotesResolvers = ResolversObject<{ + notes?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ResponseTimelineResolvers = ResolversObject<{ + code?: Resolver, ParentType, ContextType>, + message?: Resolver, ParentType, ContextType>, + timeline?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ResponseTimelinesResolvers = ResolversObject<{ + timeline?: Resolver>, ParentType, ContextType>, + totalCount?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type RuleEcsFieldResolvers = ResolversObject<{ + reference?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type RuleFieldResolvers = ResolversObject<{ + id?: Resolver, ParentType, ContextType>, + rule_id?: Resolver, ParentType, ContextType>, + false_positives?: Resolver, ParentType, ContextType>, + saved_id?: Resolver, ParentType, ContextType>, + timeline_id?: Resolver, ParentType, ContextType>, + timeline_title?: Resolver, ParentType, ContextType>, + max_signals?: Resolver, ParentType, ContextType>, + risk_score?: Resolver, ParentType, ContextType>, + output_index?: Resolver, ParentType, ContextType>, + description?: Resolver, ParentType, ContextType>, + from?: Resolver, ParentType, ContextType>, + immutable?: Resolver, ParentType, ContextType>, + index?: Resolver, ParentType, ContextType>, + interval?: Resolver, ParentType, ContextType>, + language?: Resolver, ParentType, ContextType>, + query?: Resolver, ParentType, ContextType>, + references?: Resolver, ParentType, ContextType>, + severity?: Resolver, ParentType, ContextType>, + tags?: Resolver, ParentType, ContextType>, + threat?: Resolver, ParentType, ContextType>, + type?: Resolver, ParentType, ContextType>, + size?: Resolver, ParentType, ContextType>, + to?: Resolver, ParentType, ContextType>, + enabled?: Resolver, ParentType, ContextType>, + filters?: Resolver, ParentType, ContextType>, + created_at?: Resolver, ParentType, ContextType>, + updated_at?: Resolver, ParentType, ContextType>, + created_by?: Resolver, ParentType, ContextType>, + updated_by?: Resolver, ParentType, ContextType>, + version?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SayMyNameResolvers = ResolversObject<{ + appName?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SerializedFilterQueryResultResolvers = ResolversObject<{ + filterQuery?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SerializedKueryQueryResultResolvers = ResolversObject<{ + kuery?: Resolver, ParentType, ContextType>, + serializedQuery?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SignalFieldResolvers = ResolversObject<{ + rule?: Resolver, ParentType, ContextType>, + original_time?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SortTimelineResultResolvers = ResolversObject<{ + columnId?: Resolver, ParentType, ContextType>, + sortDirection?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SourceResolvers = ResolversObject<{ + id?: Resolver, + configuration?: Resolver, + status?: Resolver, + Authentications?: Resolver>, + Timeline?: Resolver>, + TimelineDetails?: Resolver>, + LastEventTime?: Resolver>, + Hosts?: Resolver>, + HostOverview?: Resolver>, + HostFirstLastSeen?: Resolver>, + IpOverview?: Resolver, ParentType, ContextType, RequireFields>, + Users?: Resolver>, + KpiNetwork?: Resolver, ParentType, ContextType, RequireFields>, + KpiHosts?: Resolver>, + KpiHostDetails?: Resolver>, + MatrixHistogram?: Resolver>, + NetworkTopCountries?: Resolver>, + NetworkTopNFlow?: Resolver>, + NetworkDns?: Resolver>, + NetworkDnsHistogram?: Resolver>, + NetworkHttp?: Resolver>, + OverviewNetwork?: Resolver, ParentType, ContextType, RequireFields>, + OverviewHost?: Resolver, ParentType, ContextType, RequireFields>, + Tls?: Resolver>, + UncommonProcesses?: Resolver>, + whoAmI?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SourceConfigurationResolvers = ResolversObject<{ + fields?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SourceEcsFieldsResolvers = ResolversObject<{ + bytes?: Resolver, ParentType, ContextType>, + ip?: Resolver, ParentType, ContextType>, + port?: Resolver, ParentType, ContextType>, + domain?: Resolver, ParentType, ContextType>, + geo?: Resolver, ParentType, ContextType>, + packets?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SourceFieldsResolvers = ResolversObject<{ + container?: Resolver, + host?: Resolver, + message?: Resolver, ParentType, ContextType>, + pod?: Resolver, + tiebreaker?: Resolver, + timestamp?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SourceStatusResolvers = ResolversObject<{ + indicesExist?: Resolver>, + indexFields?: Resolver, ParentType, ContextType, RequireFields>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SshEcsFieldsResolvers = ResolversObject<{ + method?: Resolver, ParentType, ContextType>, + signature?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SummaryResolvers = ResolversObject<{ + actor?: Resolver, ParentType, ContextType>, + object?: Resolver, ParentType, ContextType>, + how?: Resolver, ParentType, ContextType>, + message_type?: Resolver, ParentType, ContextType>, + sequence?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SuricataAlertDataResolvers = ResolversObject<{ + signature?: Resolver, ParentType, ContextType>, + signature_id?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SuricataEcsFieldsResolvers = ResolversObject<{ + eve?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SuricataEveDataResolvers = ResolversObject<{ + alert?: Resolver, ParentType, ContextType>, + flow_id?: Resolver, ParentType, ContextType>, + proto?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type SystemEcsFieldResolvers = ResolversObject<{ + audit?: Resolver, ParentType, ContextType>, + auth?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ThreadResolvers = ResolversObject<{ + id?: Resolver, ParentType, ContextType>, + start?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TimelineDataResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + pageInfo?: Resolver, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TimelineDetailsDataResolvers = ResolversObject<{ + data?: Resolver>, ParentType, ContextType>, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TimelineEdgesResolvers = ResolversObject<{ + node?: Resolver, + cursor?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TimelineItemResolvers = ResolversObject<{ + _id?: Resolver, + _index?: Resolver, ParentType, ContextType>, + data?: Resolver, ParentType, ContextType>, + ecs?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TimelineNonEcsDataResolvers = ResolversObject<{ + field?: Resolver, + value?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TimelineResultResolvers = ResolversObject<{ + columns?: Resolver>, ParentType, ContextType>, + created?: Resolver, ParentType, ContextType>, + createdBy?: Resolver, ParentType, ContextType>, + dataProviders?: Resolver>, ParentType, ContextType>, + dateRange?: Resolver, ParentType, ContextType>, + description?: Resolver, ParentType, ContextType>, + eventIdToNoteIds?: Resolver>, ParentType, ContextType>, + eventType?: Resolver, ParentType, ContextType>, + favorite?: Resolver>, ParentType, ContextType>, + filters?: Resolver>, ParentType, ContextType>, + kqlMode?: Resolver, ParentType, ContextType>, + kqlQuery?: Resolver, ParentType, ContextType>, + notes?: Resolver>, ParentType, ContextType>, + noteIds?: Resolver>, ParentType, ContextType>, + pinnedEventIds?: Resolver>, ParentType, ContextType>, + pinnedEventsSaveObject?: Resolver>, ParentType, ContextType>, + savedQueryId?: Resolver, ParentType, ContextType>, + savedObjectId?: Resolver, + sort?: Resolver, ParentType, ContextType>, + title?: Resolver, ParentType, ContextType>, + updated?: Resolver, ParentType, ContextType>, + updatedBy?: Resolver, ParentType, ContextType>, + version?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TlsClientCertificateDataResolvers = ResolversObject<{ + fingerprint?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TlsDataResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + pageInfo?: Resolver, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TlsEcsFieldsResolvers = ResolversObject<{ + client_certificate?: Resolver, ParentType, ContextType>, + fingerprints?: Resolver, ParentType, ContextType>, + server_certificate?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TlsEdgesResolvers = ResolversObject<{ + node?: Resolver, + cursor?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TlsFingerprintsDataResolvers = ResolversObject<{ + ja3?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TlsJa3DataResolvers = ResolversObject<{ + hash?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TlsNodeResolvers = ResolversObject<{ + _id?: Resolver, ParentType, ContextType>, + timestamp?: Resolver, ParentType, ContextType>, + alternativeNames?: Resolver>, ParentType, ContextType>, + notAfter?: Resolver>, ParentType, ContextType>, + commonNames?: Resolver>, ParentType, ContextType>, + ja3?: Resolver>, ParentType, ContextType>, + issuerNames?: Resolver>, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TlsServerCertificateDataResolvers = ResolversObject<{ + fingerprint?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export interface ToAnyScalarConfig extends GraphQLScalarTypeConfig { + name: 'ToAny' +} + +export interface ToBooleanArrayScalarConfig extends GraphQLScalarTypeConfig { + name: 'ToBooleanArray' +} + +export interface ToDateArrayScalarConfig extends GraphQLScalarTypeConfig { + name: 'ToDateArray' +} + +export interface ToNumberArrayScalarConfig extends GraphQLScalarTypeConfig { + name: 'ToNumberArray' +} + +export type TopCountriesItemDestinationResolvers = ResolversObject<{ + country?: Resolver, ParentType, ContextType>, + destination_ips?: Resolver, ParentType, ContextType>, + flows?: Resolver, ParentType, ContextType>, + location?: Resolver, ParentType, ContextType>, + source_ips?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TopCountriesItemSourceResolvers = ResolversObject<{ + country?: Resolver, ParentType, ContextType>, + destination_ips?: Resolver, ParentType, ContextType>, + flows?: Resolver, ParentType, ContextType>, + location?: Resolver, ParentType, ContextType>, + source_ips?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TopNetworkTablesEcsFieldResolvers = ResolversObject<{ + bytes_in?: Resolver, ParentType, ContextType>, + bytes_out?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TopNFlowItemDestinationResolvers = ResolversObject<{ + autonomous_system?: Resolver, ParentType, ContextType>, + domain?: Resolver>, ParentType, ContextType>, + ip?: Resolver, ParentType, ContextType>, + location?: Resolver, ParentType, ContextType>, + flows?: Resolver, ParentType, ContextType>, + source_ips?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type TopNFlowItemSourceResolvers = ResolversObject<{ + autonomous_system?: Resolver, ParentType, ContextType>, + domain?: Resolver>, ParentType, ContextType>, + ip?: Resolver, ParentType, ContextType>, + location?: Resolver, ParentType, ContextType>, + flows?: Resolver, ParentType, ContextType>, + destination_ips?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export interface ToStringArrayScalarConfig extends GraphQLScalarTypeConfig { + name: 'ToStringArray' +} + +export type UncommonProcessesDataResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + pageInfo?: Resolver, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type UncommonProcessesEdgesResolvers = ResolversObject<{ + node?: Resolver, + cursor?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type UncommonProcessItemResolvers = ResolversObject<{ + _id?: Resolver, + instances?: Resolver, + process?: Resolver, + hosts?: Resolver, ParentType, ContextType>, + user?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type UrlEcsFieldsResolvers = ResolversObject<{ + domain?: Resolver, ParentType, ContextType>, + original?: Resolver, ParentType, ContextType>, + username?: Resolver, ParentType, ContextType>, + password?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type UserEcsFieldsResolvers = ResolversObject<{ + domain?: Resolver, ParentType, ContextType>, + id?: Resolver, ParentType, ContextType>, + name?: Resolver, ParentType, ContextType>, + full_name?: Resolver, ParentType, ContextType>, + email?: Resolver, ParentType, ContextType>, + hash?: Resolver, ParentType, ContextType>, + group?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type UsersDataResolvers = ResolversObject<{ + edges?: Resolver, ParentType, ContextType>, + totalCount?: Resolver, + pageInfo?: Resolver, + inspect?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type UsersEdgesResolvers = ResolversObject<{ + node?: Resolver, + cursor?: Resolver, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type UsersItemResolvers = ResolversObject<{ + name?: Resolver, ParentType, ContextType>, + id?: Resolver, ParentType, ContextType>, + groupId?: Resolver, ParentType, ContextType>, + groupName?: Resolver, ParentType, ContextType>, + count?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type UsersNodeResolvers = ResolversObject<{ + _id?: Resolver, ParentType, ContextType>, + timestamp?: Resolver, ParentType, ContextType>, + user?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type WinlogEcsFieldsResolvers = ResolversObject<{ + event_id?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ZeekConnectionDataResolvers = ResolversObject<{ + local_resp?: Resolver, ParentType, ContextType>, + local_orig?: Resolver, ParentType, ContextType>, + missed_bytes?: Resolver, ParentType, ContextType>, + state?: Resolver, ParentType, ContextType>, + history?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ZeekDnsDataResolvers = ResolversObject<{ + AA?: Resolver, ParentType, ContextType>, + qclass_name?: Resolver, ParentType, ContextType>, + RD?: Resolver, ParentType, ContextType>, + qtype_name?: Resolver, ParentType, ContextType>, + rejected?: Resolver, ParentType, ContextType>, + qtype?: Resolver, ParentType, ContextType>, + query?: Resolver, ParentType, ContextType>, + trans_id?: Resolver, ParentType, ContextType>, + qclass?: Resolver, ParentType, ContextType>, + RA?: Resolver, ParentType, ContextType>, + TC?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ZeekEcsFieldsResolvers = ResolversObject<{ + session_id?: Resolver, ParentType, ContextType>, + connection?: Resolver, ParentType, ContextType>, + notice?: Resolver, ParentType, ContextType>, + dns?: Resolver, ParentType, ContextType>, + http?: Resolver, ParentType, ContextType>, + files?: Resolver, ParentType, ContextType>, + ssl?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ZeekFileDataResolvers = ResolversObject<{ + session_ids?: Resolver, ParentType, ContextType>, + timedout?: Resolver, ParentType, ContextType>, + local_orig?: Resolver, ParentType, ContextType>, + tx_host?: Resolver, ParentType, ContextType>, + source?: Resolver, ParentType, ContextType>, + is_orig?: Resolver, ParentType, ContextType>, + overflow_bytes?: Resolver, ParentType, ContextType>, + sha1?: Resolver, ParentType, ContextType>, + duration?: Resolver, ParentType, ContextType>, + depth?: Resolver, ParentType, ContextType>, + analyzers?: Resolver, ParentType, ContextType>, + mime_type?: Resolver, ParentType, ContextType>, + rx_host?: Resolver, ParentType, ContextType>, + total_bytes?: Resolver, ParentType, ContextType>, + fuid?: Resolver, ParentType, ContextType>, + seen_bytes?: Resolver, ParentType, ContextType>, + missing_bytes?: Resolver, ParentType, ContextType>, + md5?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ZeekHttpDataResolvers = ResolversObject<{ + resp_mime_types?: Resolver, ParentType, ContextType>, + trans_depth?: Resolver, ParentType, ContextType>, + status_msg?: Resolver, ParentType, ContextType>, + resp_fuids?: Resolver, ParentType, ContextType>, + tags?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ZeekNoticeDataResolvers = ResolversObject<{ + suppress_for?: Resolver, ParentType, ContextType>, + msg?: Resolver, ParentType, ContextType>, + note?: Resolver, ParentType, ContextType>, + sub?: Resolver, ParentType, ContextType>, + dst?: Resolver, ParentType, ContextType>, + dropped?: Resolver, ParentType, ContextType>, + peer_descr?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type ZeekSslDataResolvers = ResolversObject<{ + cipher?: Resolver, ParentType, ContextType>, + established?: Resolver, ParentType, ContextType>, + resumed?: Resolver, ParentType, ContextType>, + version?: Resolver, ParentType, ContextType>, + __isTypeOf?: isTypeOfResolverFn, +}>; + +export type Resolvers = ResolversObject<{ + AuditdData?: AuditdDataResolvers, + AuditdEcsFields?: AuditdEcsFieldsResolvers, + AuditEcsFields?: AuditEcsFieldsResolvers, + AuthEcsFields?: AuthEcsFieldsResolvers, + AuthenticationItem?: AuthenticationItemResolvers, + AuthenticationsData?: AuthenticationsDataResolvers, + AuthenticationsEdges?: AuthenticationsEdgesResolvers, + AutonomousSystem?: AutonomousSystemResolvers, + AutonomousSystemItem?: AutonomousSystemItemResolvers, + AutonomousSystemOrganization?: AutonomousSystemOrganizationResolvers, + CloudFields?: CloudFieldsResolvers, + CloudInstance?: CloudInstanceResolvers, + CloudMachine?: CloudMachineResolvers, + ColumnHeaderResult?: ColumnHeaderResultResolvers, + CursorType?: CursorTypeResolvers, + DataProviderResult?: DataProviderResultResolvers, + Date?: GraphQLScalarType, + DateRangePickerResult?: DateRangePickerResultResolvers, + DestinationEcsFields?: DestinationEcsFieldsResolvers, + DetailItem?: DetailItemResolvers, + DnsEcsFields?: DnsEcsFieldsResolvers, + DnsQuestionData?: DnsQuestionDataResolvers, + ECS?: EcsResolvers, + EcsEdges?: EcsEdgesResolvers, + EndgameEcsFields?: EndgameEcsFieldsResolvers, + EsValue?: GraphQLScalarType, + EventEcsFields?: EventEcsFieldsResolvers, + EventsTimelineData?: EventsTimelineDataResolvers, + FavoriteTimelineResult?: FavoriteTimelineResultResolvers, + FileFields?: FileFieldsResolvers, + FilterMetaTimelineResult?: FilterMetaTimelineResultResolvers, + FilterTimelineResult?: FilterTimelineResultResolvers, + FingerprintData?: FingerprintDataResolvers, + FirstLastSeenHost?: FirstLastSeenHostResolvers, + GeoEcsFields?: GeoEcsFieldsResolvers, + GeoItem?: GeoItemResolvers, + HostEcsFields?: HostEcsFieldsResolvers, + HostFields?: HostFieldsResolvers, + HostItem?: HostItemResolvers, + HostsData?: HostsDataResolvers, + HostsEdges?: HostsEdgesResolvers, + HttpBodyData?: HttpBodyDataResolvers, + HttpEcsFields?: HttpEcsFieldsResolvers, + HttpRequestData?: HttpRequestDataResolvers, + HttpResponseData?: HttpResponseDataResolvers, + IndexField?: IndexFieldResolvers, + Inspect?: InspectResolvers, + IpOverviewData?: IpOverviewDataResolvers, + KpiHostDetailsData?: KpiHostDetailsDataResolvers, + KpiHostHistogramData?: KpiHostHistogramDataResolvers, + KpiHostsData?: KpiHostsDataResolvers, + KpiNetworkData?: KpiNetworkDataResolvers, + KpiNetworkHistogramData?: KpiNetworkHistogramDataResolvers, + KueryFilterQueryResult?: KueryFilterQueryResultResolvers, + LastEventTimeData?: LastEventTimeDataResolvers, + LastSourceHost?: LastSourceHostResolvers, + Location?: LocationResolvers, + MatrixHistogramOverTimeData?: MatrixHistogramOverTimeDataResolvers, + MatrixOverOrdinalHistogramData?: MatrixOverOrdinalHistogramDataResolvers, + MatrixOverTimeHistogramData?: MatrixOverTimeHistogramDataResolvers, + Mutation?: MutationResolvers, + NetworkDnsData?: NetworkDnsDataResolvers, + NetworkDnsEdges?: NetworkDnsEdgesResolvers, + NetworkDnsItem?: NetworkDnsItemResolvers, + NetworkDsOverTimeData?: NetworkDsOverTimeDataResolvers, + NetworkEcsField?: NetworkEcsFieldResolvers, + NetworkHttpData?: NetworkHttpDataResolvers, + NetworkHttpEdges?: NetworkHttpEdgesResolvers, + NetworkHttpItem?: NetworkHttpItemResolvers, + NetworkTopCountriesData?: NetworkTopCountriesDataResolvers, + NetworkTopCountriesEdges?: NetworkTopCountriesEdgesResolvers, + NetworkTopCountriesItem?: NetworkTopCountriesItemResolvers, + NetworkTopNFlowData?: NetworkTopNFlowDataResolvers, + NetworkTopNFlowEdges?: NetworkTopNFlowEdgesResolvers, + NetworkTopNFlowItem?: NetworkTopNFlowItemResolvers, + NoteResult?: NoteResultResolvers, + OsEcsFields?: OsEcsFieldsResolvers, + OsFields?: OsFieldsResolvers, + Overview?: OverviewResolvers, + OverviewHostData?: OverviewHostDataResolvers, + OverviewNetworkData?: OverviewNetworkDataResolvers, + PackageEcsFields?: PackageEcsFieldsResolvers, + PageInfo?: PageInfoResolvers, + PageInfoPaginated?: PageInfoPaginatedResolvers, + PinnedEvent?: PinnedEventResolvers, + PrimarySecondary?: PrimarySecondaryResolvers, + ProcessEcsFields?: ProcessEcsFieldsResolvers, + ProcessHashData?: ProcessHashDataResolvers, + Query?: QueryResolvers, + QueryMatchResult?: QueryMatchResultResolvers, + ResponseFavoriteTimeline?: ResponseFavoriteTimelineResolvers, + ResponseNote?: ResponseNoteResolvers, + ResponseNotes?: ResponseNotesResolvers, + ResponseTimeline?: ResponseTimelineResolvers, + ResponseTimelines?: ResponseTimelinesResolvers, + RuleEcsField?: RuleEcsFieldResolvers, + RuleField?: RuleFieldResolvers, + SayMyName?: SayMyNameResolvers, + SerializedFilterQueryResult?: SerializedFilterQueryResultResolvers, + SerializedKueryQueryResult?: SerializedKueryQueryResultResolvers, + SignalField?: SignalFieldResolvers, + SortTimelineResult?: SortTimelineResultResolvers, + Source?: SourceResolvers, + SourceConfiguration?: SourceConfigurationResolvers, + SourceEcsFields?: SourceEcsFieldsResolvers, + SourceFields?: SourceFieldsResolvers, + SourceStatus?: SourceStatusResolvers, + SshEcsFields?: SshEcsFieldsResolvers, + Summary?: SummaryResolvers, + SuricataAlertData?: SuricataAlertDataResolvers, + SuricataEcsFields?: SuricataEcsFieldsResolvers, + SuricataEveData?: SuricataEveDataResolvers, + SystemEcsField?: SystemEcsFieldResolvers, + Thread?: ThreadResolvers, + TimelineData?: TimelineDataResolvers, + TimelineDetailsData?: TimelineDetailsDataResolvers, + TimelineEdges?: TimelineEdgesResolvers, + TimelineItem?: TimelineItemResolvers, + TimelineNonEcsData?: TimelineNonEcsDataResolvers, + TimelineResult?: TimelineResultResolvers, + TlsClientCertificateData?: TlsClientCertificateDataResolvers, + TlsData?: TlsDataResolvers, + TlsEcsFields?: TlsEcsFieldsResolvers, + TlsEdges?: TlsEdgesResolvers, + TlsFingerprintsData?: TlsFingerprintsDataResolvers, + TlsJa3Data?: TlsJa3DataResolvers, + TlsNode?: TlsNodeResolvers, + TlsServerCertificateData?: TlsServerCertificateDataResolvers, + ToAny?: GraphQLScalarType, + ToBooleanArray?: GraphQLScalarType, + ToDateArray?: GraphQLScalarType, + ToNumberArray?: GraphQLScalarType, + TopCountriesItemDestination?: TopCountriesItemDestinationResolvers, + TopCountriesItemSource?: TopCountriesItemSourceResolvers, + TopNetworkTablesEcsField?: TopNetworkTablesEcsFieldResolvers, + TopNFlowItemDestination?: TopNFlowItemDestinationResolvers, + TopNFlowItemSource?: TopNFlowItemSourceResolvers, + ToStringArray?: GraphQLScalarType, + UncommonProcessesData?: UncommonProcessesDataResolvers, + UncommonProcessesEdges?: UncommonProcessesEdgesResolvers, + UncommonProcessItem?: UncommonProcessItemResolvers, + UrlEcsFields?: UrlEcsFieldsResolvers, + UserEcsFields?: UserEcsFieldsResolvers, + UsersData?: UsersDataResolvers, + UsersEdges?: UsersEdgesResolvers, + UsersItem?: UsersItemResolvers, + UsersNode?: UsersNodeResolvers, + WinlogEcsFields?: WinlogEcsFieldsResolvers, + ZeekConnectionData?: ZeekConnectionDataResolvers, + ZeekDnsData?: ZeekDnsDataResolvers, + ZeekEcsFields?: ZeekEcsFieldsResolvers, + ZeekFileData?: ZeekFileDataResolvers, + ZeekHttpData?: ZeekHttpDataResolvers, + ZeekNoticeData?: ZeekNoticeDataResolvers, + ZeekSslData?: ZeekSslDataResolvers, +}>; + + +/** + * @deprecated + * Use "Resolvers" root object instead. If you wish to get "IResolvers", add "typesPrefix: I" to your config. +*/ +export type IResolvers = Resolvers; diff --git a/x-pack/legacy/plugins/siem/server/graphql/uncommon_processes/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/uncommon_processes/resolvers.ts index 03d3c3d1a1fe4..00b34a0c5fbe5 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/uncommon_processes/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/uncommon_processes/resolvers.ts @@ -5,15 +5,8 @@ */ import { SourceResolvers } from '../../graphql/types'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; import { UncommonProcesses } from '../../lib/uncommon_processes'; import { createOptionsPaginated } from '../../utils/build_query/create_options'; -import { QuerySourceResolver } from '../sources/resolvers'; - -type QueryUncommonProcessesResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; export interface UncommonProcessesResolversDeps { uncommonProcesses: UncommonProcesses; @@ -23,7 +16,7 @@ export const createUncommonProcessesResolvers = ( libs: UncommonProcessesResolversDeps ): { Source: { - UncommonProcesses: QueryUncommonProcessesResolver; + UncommonProcesses: SourceResolvers['UncommonProcesses']; }; } => ({ Source: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/uncommon_processes/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/uncommon_processes/schema.gql.ts index 36a3da6779172..842ab80b5bd7c 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/uncommon_processes/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/uncommon_processes/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const uncommonProcessesSchema = gql` type UncommonProcessItem { diff --git a/x-pack/legacy/plugins/siem/server/graphql/who_am_i/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/who_am_i/resolvers.ts index 065edfb99ccea..8a2ecbdbd40bb 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/who_am_i/resolvers.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/who_am_i/resolvers.ts @@ -5,17 +5,10 @@ */ import { SourceResolvers } from '../../graphql/types'; -import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; -import { QuerySourceResolver } from '../sources/resolvers'; - -export type QueryWhoAmIResolver = ChildResolverOf< - AppResolverOf, - QuerySourceResolver ->; export const createWhoAmIResolvers = (): { Source: { - whoAmI: QueryWhoAmIResolver; + whoAmI: SourceResolvers['whoAmI']; }; } => ({ Source: { diff --git a/x-pack/legacy/plugins/siem/server/graphql/who_am_i/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/who_am_i/schema.gql.ts index 0a264cd2988fe..e2c57fe4b5634 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/who_am_i/schema.gql.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/who_am_i/schema.gql.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; export const whoAmISchema = gql` type SayMyName { diff --git a/x-pack/legacy/plugins/siem/server/init_server.ts b/x-pack/legacy/plugins/siem/server/init_server.ts index 6158a33c25cfa..83c5f0c171c8a 100644 --- a/x-pack/legacy/plugins/siem/server/init_server.ts +++ b/x-pack/legacy/plugins/siem/server/init_server.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { IResolvers, makeExecutableSchema } from 'graphql-tools'; +import { IResolvers, makeExecutableSchema } from '@kamilkisiela/graphql-tools'; import { schemas } from './graphql'; import { createAuthenticationsResolvers } from './graphql/authentications'; diff --git a/x-pack/legacy/plugins/siem/server/lib/framework/types.ts b/x-pack/legacy/plugins/siem/server/lib/framework/types.ts index 7d049d1dcd195..b72dc9ef580d7 100644 --- a/x-pack/legacy/plugins/siem/server/lib/framework/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/framework/types.ts @@ -6,6 +6,7 @@ import { IndicesGetMappingParams } from 'elasticsearch'; import { GraphQLSchema } from 'graphql'; +import * as runtimeTypes from 'io-ts'; import { RequestHandlerContext, KibanaRequest } from '../../../../../../../src/core/server'; import { AuthenticatedUser } from '../../../../../../plugins/security/common/model'; @@ -20,8 +21,6 @@ import { HistogramType, } from '../../graphql/types'; -export * from '../../utils/typed_resolvers'; - export const internalFrameworkRequest = Symbol('internalFrameworkRequest'); export interface FrameworkAdapter { @@ -133,3 +132,6 @@ export interface RequestOptionsPaginated extends RequestBasicOptions { fields: readonly string[]; sortField?: SortField; } + +export const unionWithNullType = (type: T) => + runtimeTypes.union([type, runtimeTypes.null]); diff --git a/x-pack/legacy/plugins/siem/server/utils/typed_resolvers.ts b/x-pack/legacy/plugins/siem/server/utils/typed_resolvers.ts deleted file mode 100644 index da38e8a1e1bf2..0000000000000 --- a/x-pack/legacy/plugins/siem/server/utils/typed_resolvers.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import * as runtimeTypes from 'io-ts'; -import { GraphQLResolveInfo } from 'graphql'; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type Resolver = ( - parent: Parent, - args: Args, - context: TContext, - info: GraphQLResolveInfo -) => Promise | Result; - -type ResolverResult = R | Promise; - -type AppResolverResult = - | Promise - | Promise<{ [P in keyof R]: () => Promise }> - | { [P in keyof R]: () => Promise } - | { [P in keyof R]: () => R[P] } - | R; - -export type ResultOf = Resolver_ extends Resolver> - ? Result - : never; - -export type SubsetResolverWithFields = R extends Resolver< - Array, - infer ParentInArray, - infer ContextInArray, - infer ArgsInArray -> - ? Resolver< - Array>>, - ParentInArray, - ContextInArray, - ArgsInArray - > - : R extends Resolver - ? Resolver>, Parent, Context, Args> - : never; - -export type SubsetResolverWithoutFields = R extends Resolver< - Array, - infer ParentInArray, - infer ContextInArray, - infer ArgsInArray -> - ? Resolver< - Array>>, - ParentInArray, - ContextInArray, - ArgsInArray - > - : R extends Resolver - ? Resolver>, Parent, Context, Args> - : never; - -export type ResolverWithParent = Resolver_ extends Resolver< - infer Result, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - any, - infer Context, - infer Args -> - ? Resolver - : never; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type AppResolver = Resolver< - AppResolverResult, - Parent, - Context, - Args ->; - -export type AppResolverOf = Resolver_ extends Resolver< - ResolverResult, - never, - infer ContextWithNeverParent, - infer ArgsWithNeverParent -> - ? AppResolver - : Resolver_ extends Resolver< - ResolverResult, - infer Parent, - infer Context, - infer Args - > - ? AppResolver - : never; - -export type AppResolverWithFields = AppResolverOf< - SubsetResolverWithFields ->; - -export type AppResolverWithoutFields = AppResolverOf< - SubsetResolverWithoutFields ->; - -export type ChildResolverOf = ResolverWithParent< - Resolver_, - ResultOf ->; - -export const unionWithNullType = (type: T) => - runtimeTypes.union([type, runtimeTypes.null]); diff --git a/x-pack/package.json b/x-pack/package.json index 96e06dd71b3fe..5d0ac156f87fa 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -27,6 +27,17 @@ }, "devDependencies": { "@cypress/webpack-preprocessor": "^4.1.0", + "@graphql-codegen/add": "^1.12.2", + "@graphql-codegen/core": "^1.12.2", + "@graphql-codegen/typescript": "^1.12.2", + "@graphql-codegen/typescript-compatibility": "^1.12.2", + "@graphql-codegen/typescript-operations": "^1.12.2", + "@graphql-codegen/typescript-resolvers": "^1.12.2", + "@graphql-codegen/typescript-react-apollo": "^1.12.2", + "@graphql-toolkit/code-file-loader": "^0.9.7", + "@graphql-toolkit/common":"^0.9.7", + "@graphql-toolkit/core": "^0.9.7", + "@graphql-toolkit/graphql-file-loader": "^0.9.7", "@kbn/dev-utils": "1.0.0", "@kbn/es": "1.0.0", "@kbn/expect": "1.0.0", @@ -62,7 +73,6 @@ "@types/getos": "^3.0.0", "@types/git-url-parse": "^9.0.0", "@types/glob": "^7.1.1", - "@types/graphql": "^0.13.2", "@types/gulp": "^4.0.6", "@types/hapi__wreck": "^15.0.1", "@types/hoist-non-react-statics": "^3.3.1", @@ -173,6 +183,8 @@ "yargs": "4.8.1" }, "dependencies": { + "@apollo/client": "^3.0.0-beta.37", + "@apollo/react-components": "^3.2.0-beta.1", "@babel/core": "^7.5.5", "@babel/register": "^7.7.0", "@babel/runtime": "^7.5.5", @@ -184,6 +196,7 @@ "@elastic/maki": "6.1.0", "@elastic/node-crypto": "^1.0.0", "@elastic/numeral": "2.4.0", + "@kamilkisiela/graphql-tools": "^4.0.6", "@kbn/babel-preset": "1.0.0", "@kbn/config-schema": "1.0.0", "@kbn/i18n": "1.0.0", @@ -201,8 +214,8 @@ "angular-ui-ace": "0.2.3", "apollo-cache-inmemory": "1.6.2", "apollo-client": "^2.3.8", - "apollo-link": "^1.2.3", - "apollo-link-error": "^1.1.7", + "apollo-link": "^1.2.13", + "apollo-link-error": "^2.0.0-beta.0", "apollo-link-http": "^1.5.16", "apollo-link-schema": "^1.1.0", "apollo-link-state": "^0.4.1", @@ -241,10 +254,10 @@ "git-url-parse": "11.1.2", "github-markdown-css": "^2.10.0", "glob": "^7.1.2", - "graphql": "^0.13.2", + "graphql": "^14.6.0", "graphql-fields": "^1.0.2", - "graphql-tag": "^2.9.2", - "graphql-tools": "^3.0.2", + "graphql-tag": "^2.10.3", + "graphql-tools": "^4.0.6", "h2o2": "^8.1.2", "handlebars": "4.5.3", "history": "4.9.0", diff --git a/x-pack/test/api_integration/apis/siem/feature_controls.ts b/x-pack/test/api_integration/apis/siem/feature_controls.ts index 1623a2b286f79..35a8bbca2ff5d 100644 --- a/x-pack/test/api_integration/apis/siem/feature_controls.ts +++ b/x-pack/test/api_integration/apis/siem/feature_controls.ts @@ -5,7 +5,7 @@ */ import expect from '@kbn/expect'; -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; import { FtrProviderContext } from '../../ftr_provider_context'; const introspectionQuery = gql` diff --git a/x-pack/test/api_integration/apis/siem/saved_objects/notes.ts b/x-pack/test/api_integration/apis/siem/saved_objects/notes.ts index 5aa7a10e07c2a..97ed58ae0a45e 100644 --- a/x-pack/test/api_integration/apis/siem/saved_objects/notes.ts +++ b/x-pack/test/api_integration/apis/siem/saved_objects/notes.ts @@ -5,7 +5,7 @@ */ import expect from '@kbn/expect'; -import gql from 'graphql-tag'; +import { gql } from '@apollo/client'; import { FtrProviderContext } from '../../../ftr_provider_context'; import { persistTimelineNoteMutation } from '../../../../../legacy/plugins/siem/public/containers/timeline/notes/persist.gql_query'; diff --git a/x-pack/test/api_integration/apis/siem/saved_objects/timeline.ts b/x-pack/test/api_integration/apis/siem/saved_objects/timeline.ts index a6ced270e2132..98fc86632a3fd 100644 --- a/x-pack/test/api_integration/apis/siem/saved_objects/timeline.ts +++ b/x-pack/test/api_integration/apis/siem/saved_objects/timeline.ts @@ -11,7 +11,7 @@ */ import expect from '@kbn/expect'; -import ApolloClient from 'apollo-client'; +import { ApolloClient } from '@apollo/client'; import { FtrProviderContext } from '../../../ftr_provider_context'; diff --git a/x-pack/test/api_integration/services/siem_graphql_client.ts b/x-pack/test/api_integration/services/siem_graphql_client.ts index 7d6aa5e8a9dd5..6668aa89852a3 100644 --- a/x-pack/test/api_integration/services/siem_graphql_client.ts +++ b/x-pack/test/api_integration/services/siem_graphql_client.ts @@ -6,12 +6,9 @@ import { format as formatUrl } from 'url'; import fetch from 'node-fetch'; -import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; -import { ApolloClient } from 'apollo-client'; -import { HttpLink } from 'apollo-link-http'; +import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'; import { FtrProviderContext } from '../ftr_provider_context'; -import introspectionQueryResultData from '../../../legacy/plugins/siem/public/graphql/introspection.json'; interface SiemGraphQLClientFactoryOptions { username?: string; @@ -44,11 +41,7 @@ export function SiemGraphQLClientFactoryProvider({ getService }: FtrProviderCont }); return new ApolloClient({ - cache: new InMemoryCache({ - fragmentMatcher: new IntrospectionFragmentMatcher({ - introspectionQueryResultData, - }), - }), + cache: new InMemoryCache({}), link: httpLink, }); }; diff --git a/yarn.lock b/yarn.lock index 7f38495c20f4a..f3777830ecce2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,49 @@ # yarn lockfile v1 +"@apollo/client@^3.0.0-beta.10", "@apollo/client@^3.0.0-beta.23", "@apollo/client@^3.0.0-beta.37": + version "3.0.0-beta.37" + resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.0.0-beta.37.tgz#24d4eacebc2dd0d6c27e87b8aacbb5323c0d29d6" + integrity sha512-EVarxDX4dG51IHs9DyivYZQN51U2eu9deWRyAI9xkp6Y5vwmTfAcfMYQIxc/ZZhiFAq4MEk0EPLtU2kOfTILjQ== + dependencies: + "@types/zen-observable" "^0.8.0" + "@wry/equality" "^0.1.9" + fast-json-stable-stringify "^2.0.0" + graphql-tag "^2.10.2" + optimism "^0.11.5" + symbol-observable "^1.2.0" + ts-invariant "^0.4.4" + tslib "^1.10.0" + zen-observable "^0.8.14" + +"@apollo/react-common@^3.2.0-beta.1": + version "3.2.0-beta.1" + resolved "https://registry.yarnpkg.com/@apollo/react-common/-/react-common-3.2.0-beta.1.tgz#91227dde37759d9af577a8f397749deb0c5286eb" + integrity sha512-ZXkzQHZOA5WrIrIzYmltEXc22iZNWcgTdFEyMi2AwhoMdv/w89UXO7+QQ+2Fav7LgJ8zEE+znv+6D7DmKpJVvg== + dependencies: + "@apollo/client" "^3.0.0-beta.23" + +"@apollo/react-components@^3.2.0-beta.1": + version "3.2.0-beta.1" + resolved "https://registry.yarnpkg.com/@apollo/react-components/-/react-components-3.2.0-beta.1.tgz#21e2bf33ad52d9c8b46c0fa922cc3f6251775390" + integrity sha512-klPUqS8JMR57xuVUvY53EFwa4SrNBGczSL44eNc37MC4nnYGm8oH/yg73zqAf+XsiJZfXq/cgNJi5LBy0p69Lg== + dependencies: + "@apollo/react-common" "^3.2.0-beta.1" + prop-types "^15.7.2" + ts-invariant "^0.4.4" + tslib "^1.10.0" + +"@ardatan/graphql-tools@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@ardatan/graphql-tools/-/graphql-tools-4.1.0.tgz#183508ef4e3d4966f763cb1634a81be1c1255f8d" + integrity sha512-0b+KH5RZN9vCMpEjxrwFwZ7v3K6QDjs1EH+R6eRrgKMR2X274JWqYraHKLWE1uJ8iwrkRaOYfCV12jLVuvWS+A== + dependencies: + apollo-link "^1.2.3" + apollo-utilities "^1.0.1" + deprecated-decorator "^0.1.6" + iterall "^1.1.3" + uuid "^3.1.0" + "@babel/cli@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.5.5.tgz#bdb6d9169e93e241a08f5f7b0265195bf38ef5ec" @@ -26,6 +69,13 @@ dependencies: "@babel/highlight" "^7.0.0" +"@babel/code-frame@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== + dependencies: + "@babel/highlight" "^7.8.3" + "@babel/core@7.5.5", "@babel/core@^7.0.0", "@babel/core@^7.1.0", "@babel/core@^7.4.3", "@babel/core@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.5.tgz#17b2686ef0d6bc58f963dddd68ab669755582c30" @@ -77,6 +127,16 @@ source-map "^0.5.0" trim-right "^1.0.1" +"@babel/generator@^7.5.0", "@babel/generator@^7.8.3", "@babel/generator@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e" + integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA== + dependencies: + "@babel/types" "^7.8.3" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + "@babel/generator@^7.6.0", "@babel/generator@^7.6.2": version "7.6.2" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.6.2.tgz#dac8a3c2df118334c2a29ff3446da1636a8f8c03" @@ -121,6 +181,13 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-annotate-as-pure@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" + integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== + dependencies: + "@babel/types" "^7.8.3" + "@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" @@ -171,6 +238,15 @@ "@babel/traverse" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/helper-call-delegate@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692" + integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A== + dependencies: + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + "@babel/helper-create-class-features-plugin@^7.4.4", "@babel/helper-create-class-features-plugin@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.5.5.tgz#401f302c8ddbc0edd36f7c6b2887d8fa1122e5a4" @@ -195,6 +271,18 @@ "@babel/helper-replace-supers" "^7.7.4" "@babel/helper-split-export-declaration" "^7.7.4" +"@babel/helper-create-class-features-plugin@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz#5b94be88c255f140fd2c10dd151e7f98f4bff397" + integrity sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/helper-create-regexp-features-plugin@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz#6d5762359fd34f4da1500e4cff9955b5299aaf59" @@ -221,6 +309,15 @@ "@babel/types" "^7.7.4" lodash "^4.17.13" +"@babel/helper-define-map@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" + integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/types" "^7.8.3" + lodash "^4.17.13" + "@babel/helper-explode-assignable-expression@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" @@ -255,6 +352,15 @@ "@babel/template" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/helper-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" + integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + "@babel/helper-get-function-arity@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" @@ -269,6 +375,13 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-get-function-arity@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" + integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== + dependencies: + "@babel/types" "^7.8.3" + "@babel/helper-hoist-variables@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a" @@ -283,6 +396,13 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-hoist-variables@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" + integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg== + dependencies: + "@babel/types" "^7.8.3" + "@babel/helper-member-expression-to-functions@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz#1fb5b8ec4453a93c439ee9fe3aeea4a84b76b590" @@ -297,6 +417,13 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-member-expression-to-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" + integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== + dependencies: + "@babel/types" "^7.8.3" + "@babel/helper-module-imports@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" @@ -311,6 +438,13 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-module-imports@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" + integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== + dependencies: + "@babel/types" "^7.8.3" + "@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz#f84ff8a09038dcbca1fd4355661a500937165b4a" @@ -323,10 +457,22 @@ "@babel/types" "^7.5.5" lodash "^4.17.13" -"@babel/helper-module-transforms@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.7.4.tgz#8d7cdb1e1f8ea3d8c38b067345924ac4f8e0879a" - integrity sha512-ehGBu4mXrhs0FxAqN8tWkzF8GSIGAiEumu4ONZ/hD9M88uHcD+Yu2ttKfOCgwzoesJOJrtQh7trI5YPbRtMmnA== +"@babel/helper-module-transforms@^7.7.4", "@babel/helper-module-transforms@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590" + integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + lodash "^4.17.13" + +"@babel/helper-module-transforms@^7.7.5": + version "7.7.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.7.5.tgz#d044da7ffd91ec967db25cd6748f704b6b244835" + integrity sha512-A7pSxyJf1gN5qXVcidwLWydjftUN878VkalhXX5iQDuGyiGK3sOrrKKHF4/A4fwHtnsotv/NipwAeLzY4KQPvw== dependencies: "@babel/helper-module-imports" "^7.7.4" "@babel/helper-simple-access" "^7.7.4" @@ -349,11 +495,23 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-optimise-call-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" + integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== + dependencies: + "@babel/types" "^7.8.3" + "@babel/helper-plugin-utils@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== +"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" + integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== + "@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.5.5.tgz#0aa6824f7100a2e0e89c1527c23936c152cab351" @@ -361,6 +519,13 @@ dependencies: lodash "^4.17.13" +"@babel/helper-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" + integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ== + dependencies: + lodash "^4.17.13" + "@babel/helper-remap-async-to-generator@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" @@ -372,16 +537,16 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-remap-async-to-generator@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz#c68c2407350d9af0e061ed6726afb4fff16d0234" - integrity sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw== +"@babel/helper-remap-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86" + integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA== dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-wrap-function" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-wrap-function" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" "@babel/helper-replace-supers@^7.5.5": version "7.5.5" @@ -403,6 +568,16 @@ "@babel/traverse" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/helper-replace-supers@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc" + integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + "@babel/helper-simple-access@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" @@ -419,6 +594,14 @@ "@babel/template" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/helper-simple-access@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" + integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== + dependencies: + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + "@babel/helper-split-export-declaration@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" @@ -433,6 +616,13 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-split-export-declaration@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" + integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== + dependencies: + "@babel/types" "^7.8.3" + "@babel/helper-wrap-function@^7.1.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" @@ -443,15 +633,15 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.2.0" -"@babel/helper-wrap-function@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz#37ab7fed5150e22d9d7266e830072c0cdd8baace" - integrity sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg== +"@babel/helper-wrap-function@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" + integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ== dependencies: - "@babel/helper-function-name" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-function-name" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" "@babel/helpers@^7.5.5": version "7.5.5" @@ -480,30 +670,49 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/highlight@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" + integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081" + integrity sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ== + "@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.4.4", "@babel/parser@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.5.tgz#02f077ac8817d3df4a832ef59de67565e71cca4b" integrity sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g== -"@babel/parser@^7.2.0", "@babel/parser@^7.6.2": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.2.tgz#205e9c95e16ba3b8b96090677a67c9d6075b70a1" - integrity sha512-mdFqWrSPCmikBoaBYMuBulzTIKuXVPtEISFbRRVNwMWpCms/hmE2kRq0bblUHaNRKrjRlmVbx1sDHmjmRgD2Xg== +"@babel/parser@^7.2.0", "@babel/parser@^7.7.4": + version "7.7.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.5.tgz#cbf45321619ac12d83363fcf9c94bb67fa646d71" + integrity sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig== "@babel/parser@^7.6.0": version "7.6.0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.0.tgz#3e05d0647432a8326cb28d0de03895ae5a57f39b" integrity sha512-+o2q111WEx4srBs7L9eJmcwi655eD8sXniLqMB93TBK9GrNzGrxDWSjiqz2hLU0Ha8MTXFIP0yd9fNdP+m43ZQ== +"@babel/parser@^7.6.2": + version "7.6.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.2.tgz#205e9c95e16ba3b8b96090677a67c9d6075b70a1" + integrity sha512-mdFqWrSPCmikBoaBYMuBulzTIKuXVPtEISFbRRVNwMWpCms/hmE2kRq0bblUHaNRKrjRlmVbx1sDHmjmRgD2Xg== + "@babel/parser@^7.6.3": version "7.6.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.4.tgz#cb9b36a7482110282d5cb6dd424ec9262b473d81" integrity sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A== -"@babel/parser@^7.7.4": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.5.tgz#cbf45321619ac12d83363fcf9c94bb67fa646d71" - integrity sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig== +"@babel/parser@^7.8.3", "@babel/parser@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8" + integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw== "@babel/plugin-proposal-async-generator-functions@^7.2.0": version "7.2.0" @@ -515,15 +724,15 @@ "@babel/plugin-syntax-async-generators" "^7.2.0" "@babel/plugin-proposal-async-generator-functions@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz#0351c5ac0a9e927845fffd5b82af476947b7ce6d" - integrity sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw== + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" + integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.7.4" - "@babel/plugin-syntax-async-generators" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" -"@babel/plugin-proposal-class-properties@7.5.5", "@babel/plugin-proposal-class-properties@^7.3.3", "@babel/plugin-proposal-class-properties@^7.5.1", "@babel/plugin-proposal-class-properties@^7.5.5": +"@babel/plugin-proposal-class-properties@7.5.5", "@babel/plugin-proposal-class-properties@^7.3.3": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.5.5.tgz#a974cfae1e37c3110e71f3c6a2e48b8e71958cd4" integrity sha512-AF79FsnWFxjlaosgdi421vmYG6/jg79bVD0dpD44QdgobzHKuLZ6S3vl8la9qIeSwGi8i1fS0O1mfuDAAdo1/A== @@ -531,7 +740,7 @@ "@babel/helper-create-class-features-plugin" "^7.5.5" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-proposal-class-properties@^7.7.0": +"@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.5.1", "@babel/plugin-proposal-class-properties@^7.5.5": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.7.4.tgz#2f964f0cb18b948450362742e33e15211e77c2ba" integrity sha512-EcuXeV4Hv1X3+Q1TsuOmyyxeTRiSqurGJ26+I/FW1WbymmRRapVORm6x1Zl3iDIHyRxEs+VXWp6qnlcfcJSbbw== @@ -539,6 +748,14 @@ "@babel/helper-create-class-features-plugin" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-proposal-class-properties@^7.7.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz#5e06654af5cd04b608915aada9b2a6788004464e" + integrity sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-proposal-decorators@7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.4.4.tgz#de9b2a1a8ab0196f378e2a82f10b6e2a36f21cc0" @@ -581,12 +798,12 @@ "@babel/plugin-syntax-json-strings" "^7.7.4" "@babel/plugin-proposal-nullish-coalescing-operator@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.4.4.tgz#41c360d59481d88e0ce3a3f837df10121a769b39" - integrity sha512-Amph7Epui1Dh/xxUxS2+K22/MUi6+6JVTvy3P58tja3B6yKTSjwwx0/d83rF7551D6PVSSoplQb8GCwqec7HRw== + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.7.4.tgz#7db302c83bc30caa89e38fee935635ef6bd11c28" + integrity sha512-TbYHmr1Gl1UC7Vo2HVuj/Naci5BEGNZ0AJhzqD2Vpr6QPFWpUmBRLrIDjedzx7/CShq0bRDS2gI4FIs77VHLVQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.2.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.7.4" "@babel/plugin-proposal-object-rest-spread@7.5.5", "@babel/plugin-proposal-object-rest-spread@^7.3.2", "@babel/plugin-proposal-object-rest-spread@^7.5.5": version "7.5.5" @@ -596,7 +813,7 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" -"@babel/plugin-proposal-object-rest-spread@^7.6.2", "@babel/plugin-proposal-object-rest-spread@^7.7.4": +"@babel/plugin-proposal-object-rest-spread@^7.0.0": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.7.4.tgz#cc57849894a5c774214178c8ab64f6334ec8af71" integrity sha512-rnpnZR3/iWKmiQyJ3LKJpSwLDcX/nSXhdLk4Aq/tXOApIvyu7qoabrige0ylsAJffaUC51WiBu209Q0U+86OWQ== @@ -604,6 +821,14 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.7.4" +"@babel/plugin-proposal-object-rest-spread@^7.6.2", "@babel/plugin-proposal-object-rest-spread@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb" + integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-proposal-optional-catch-binding@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" @@ -621,12 +846,12 @@ "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" "@babel/plugin-proposal-optional-chaining@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.6.0.tgz#e9bf1f9b9ba10c77c033082da75f068389041af8" - integrity sha512-kj4gkZ6qUggkprRq3Uh5KP8XnE1MdIO0J7MhdDX8+rAbB6dJ2UrensGIS+0NPZAaaJ1Vr0PN6oLUgXMU1uMcSg== + version "7.7.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.7.5.tgz#f0835f044cef85b31071a924010a2a390add11d4" + integrity sha512-sOwFqT8JSchtJeDD+CjmWCaiFoLxY4Ps7NjvwHC/U7l4e9i5pTRNt8nDMIFSOUL+ncFbYSwruHM8WknYItWdXw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-chaining" "^7.2.0" + "@babel/plugin-syntax-optional-chaining" "^7.7.4" "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.4.4" @@ -652,10 +877,17 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-async-generators@^7.7.4": +"@babel/plugin-syntax-async-generators@^7.7.4", "@babel/plugin-syntax-async-generators@^7.8.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.0.0": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz#331aaf310a10c80c44a66b238b6e49132bd3c889" - integrity sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g== + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.7.4.tgz#6048c129ea908a432a1ff85f1dc794dc62ddaa5e" + integrity sha512-JH3v5ZOeKT0qqdJ9BeBcZTFQiJOMax8RopSr1bH6ASkZKo2qWsvBML7W1mp89sszBRDBBRO8snqcByGdrMTdMg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -674,9 +906,16 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-dynamic-import@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-flow@^7.0.0": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz#29ca3b4415abfe4a5ec381e903862ad1a54c3aec" - integrity sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg== + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.7.4.tgz#6d91b59e1a0e4c17f36af2e10dd64ef220919d7b" + integrity sha512-2AMAWl5PsmM5KPkB22cvOkUyWk6MjUaqhHNU5nSPUl/ns3j5qLfw2SuYP5RbVZ0tfLvePr4zUScbICtDP2CUNw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -687,17 +926,17 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-json-strings@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" - integrity sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg== +"@babel/plugin-syntax-json-strings@^7.2.0", "@babel/plugin-syntax-json-strings@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz#86e63f7d2e22f9e27129ac4e83ea989a382e86cc" + integrity sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-json-strings@^7.7.4": +"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.7.4": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz#86e63f7d2e22f9e27129ac4e83ea989a382e86cc" - integrity sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg== + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.7.4.tgz#dab2b56a36fb6c3c222a1fbc71f7bf97f327a9ec" + integrity sha512-wuy6fiMe9y7HeZBWXYCGt2RGxZOj0BImZ9EyXJVnVGBKO/Br592rbR3rtIQn0eQhAk9vqaKP5n8tVqEFBQMfLg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -708,17 +947,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-jsx@^7.7.4": +"@babel/plugin-syntax-nullish-coalescing-operator@^7.7.4": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.7.4.tgz#dab2b56a36fb6c3c222a1fbc71f7bf97f327a9ec" - integrity sha512-wuy6fiMe9y7HeZBWXYCGt2RGxZOj0BImZ9EyXJVnVGBKO/Br592rbR3rtIQn0eQhAk9vqaKP5n8tVqEFBQMfLg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.2.0.tgz#f75083dfd5ade73e783db729bbd87e7b9efb7624" - integrity sha512-lRCEaKE+LTxDQtgbYajI04ddt6WW0WJq57xqkAZ+s11h4YgfRHhVA/Y2VhfPzzFD4qeLHWg32DMp9HooY4Kqlg== + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.7.4.tgz#e53b751d0c3061b1ba3089242524b65a7a9da12b" + integrity sha512-XKh/yIRPiQTOeBg0QJjEus5qiSKucKAiApNtO1psqG7D17xmE+X2i5ZqBEuSvo0HRuyPaKaSN/Gy+Ha9KFQolw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -736,6 +968,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-object-rest-spread@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" @@ -744,16 +983,16 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-optional-catch-binding@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz#a3e38f59f4b6233867b4a92dcb0ee05b2c334aa6" - integrity sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ== + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-chaining@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.2.0.tgz#a59d6ae8c167e7608eaa443fda9fa8fa6bf21dff" - integrity sha512-HtGCtvp5Uq/jH/WNUPkK6b7rufnCPLLlDAFN7cmACoIjaOOiXxUt3SswU5loHqrhtqTsa/WoLQ1OQ1AGuZqaWA== +"@babel/plugin-syntax-optional-chaining@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.7.4.tgz#c91fdde6de85d2eb8906daea7b21944c3610c901" + integrity sha512-2MqYD5WjZSbJdUagnJvIdSfkb/ucOC9/1fRJxm7GAxY6YQLWlUvkfxoNbUPcPLHJyetKUDQ4+yyuUyAoc0HriA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -778,6 +1017,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-arrow-functions@^7.0.0", "@babel/plugin-transform-arrow-functions@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz#76309bd578addd8aee3b379d809c802305a98a12" + integrity sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-arrow-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" @@ -785,13 +1031,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-arrow-functions@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz#76309bd578addd8aee3b379d809c802305a98a12" - integrity sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-async-to-generator@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e" @@ -802,13 +1041,20 @@ "@babel/helper-remap-async-to-generator" "^7.1.0" "@babel/plugin-transform-async-to-generator@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" + integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + +"@babel/plugin-transform-block-scoped-functions@^7.0.0": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz#694cbeae6d613a34ef0292713fa42fb45c4470ba" - integrity sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz#d0d9d5c269c78eaea76227ace214b8d01e4d837b" + integrity sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ== dependencies: - "@babel/helper-module-imports" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.7.4" "@babel/plugin-transform-block-scoped-functions@^7.2.0": version "7.2.0" @@ -818,11 +1064,19 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-block-scoped-functions@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" + integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-block-scoping@^7.0.0": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz#d0d9d5c269c78eaea76227ace214b8d01e4d837b" - integrity sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz#200aad0dcd6bb80372f94d9e628ea062c58bf224" + integrity sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" + lodash "^4.17.13" "@babel/plugin-transform-block-scoping@^7.5.5": version "7.5.5" @@ -841,12 +1095,26 @@ lodash "^4.17.13" "@babel/plugin-transform-block-scoping@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" + integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + lodash "^4.17.13" + +"@babel/plugin-transform-classes@^7.0.0": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz#200aad0dcd6bb80372f94d9e628ea062c58bf224" - integrity sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz#c92c14be0a1399e15df72667067a8f510c9400ec" + integrity sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg== dependencies: + "@babel/helper-annotate-as-pure" "^7.7.4" + "@babel/helper-define-map" "^7.7.4" + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-optimise-call-expression" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - lodash "^4.17.13" + "@babel/helper-replace-supers" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + globals "^11.1.0" "@babel/plugin-transform-classes@^7.5.5": version "7.5.5" @@ -863,18 +1131,25 @@ globals "^11.1.0" "@babel/plugin-transform-classes@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8" + integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-define-map" "^7.8.3" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.0.0", "@babel/plugin-transform-computed-properties@^7.7.4": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz#c92c14be0a1399e15df72667067a8f510c9400ec" - integrity sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz#e856c1628d3238ffe12d668eb42559f79a81910d" + integrity sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-define-map" "^7.7.4" - "@babel/helper-function-name" "^7.7.4" - "@babel/helper-optimise-call-expression" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.7.4" - "@babel/helper-split-export-declaration" "^7.7.4" - globals "^11.1.0" "@babel/plugin-transform-computed-properties@^7.2.0": version "7.2.0" @@ -883,13 +1158,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-computed-properties@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz#e856c1628d3238ffe12d668eb42559f79a81910d" - integrity sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-destructuring@7.5.0", "@babel/plugin-transform-destructuring@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz#f6c09fdfe3f94516ff074fe877db7bc9ef05855a" @@ -897,6 +1165,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-destructuring@^7.0.0", "@babel/plugin-transform-destructuring@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz#2b713729e5054a1135097b6a67da1b6fe8789267" + integrity sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-destructuring@^7.6.0": version "7.6.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.6.0.tgz#44bbe08b57f4480094d57d9ffbcd96d309075ba6" @@ -904,13 +1179,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-destructuring@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz#2b713729e5054a1135097b6a67da1b6fe8789267" - integrity sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz#361a148bc951444312c69446d76ed1ea8e4450c3" @@ -966,6 +1234,13 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-flow" "^7.2.0" +"@babel/plugin-transform-for-of@^7.0.0": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz#248800e3a5e507b1f103d8b4ca998e77c63932bc" + integrity sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-for-of@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556" @@ -974,10 +1249,18 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-for-of@^7.7.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz#6fe8eae5d6875086ee185dd0b098a8513783b47d" + integrity sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-function-name@^7.0.0": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz#248800e3a5e507b1f103d8b4ca998e77c63932bc" - integrity sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz#75a6d3303d50db638ff8b5385d12451c865025b1" + integrity sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g== dependencies: + "@babel/helper-function-name" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-function-name@^7.4.4": @@ -989,11 +1272,18 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-function-name@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" + integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-literals@^7.0.0": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz#75a6d3303d50db638ff8b5385d12451c865025b1" - integrity sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz#27fe87d2b5017a2a5a34d1c41a6b9f6a6262643e" + integrity sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw== dependencies: - "@babel/helper-function-name" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-literals@^7.2.0": @@ -1004,9 +1294,16 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-literals@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" + integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-member-expression-literals@^7.0.0", "@babel/plugin-transform-member-expression-literals@^7.7.4": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz#27fe87d2b5017a2a5a34d1c41a6b9f6a6262643e" - integrity sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.7.4.tgz#aee127f2f3339fc34ce5e3055d7ffbf7aa26f19a" + integrity sha512-9VMwMO7i69LHTesL0RdGy93JU6a+qOPuvB4F4d0kR0zyVjJRVJRaoaGjhtki6SzQUu8yen/vxPKN6CWnCUw6bA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -1017,13 +1314,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-member-expression-literals@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.7.4.tgz#aee127f2f3339fc34ce5e3055d7ffbf7aa26f19a" - integrity sha512-9VMwMO7i69LHTesL0RdGy93JU6a+qOPuvB4F4d0kR0zyVjJRVJRaoaGjhtki6SzQUu8yen/vxPKN6CWnCUw6bA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-modules-amd@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91" @@ -1034,12 +1324,22 @@ babel-plugin-dynamic-import-node "^2.3.0" "@babel/plugin-transform-modules-amd@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.4.tgz#276b3845ca2b228f2995e453adc2e6f54d72fb71" - integrity sha512-/542/5LNA18YDtg1F+QHvvUSlxdvjZoD/aldQwkq+E3WCkbEjNSN9zdrOXaSlfg3IfGi22ijzecklF/A7kVZFQ== + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5" + integrity sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ== dependencies: - "@babel/helper-module-transforms" "^7.7.4" + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-commonjs@^7.0.0": + version "7.7.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.5.tgz#1d27f5eb0bcf7543e774950e5b2fa782e637b345" + integrity sha512-9Cq4zTFExwFhQI6MT1aFxgqhIsMWQWDVwOgLzl7PTWJHsNaqFvklAU+Oz6AQLAS0dJKTwZSOCo20INwktxpi3Q== + dependencies: + "@babel/helper-module-transforms" "^7.7.5" "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-simple-access" "^7.7.4" babel-plugin-dynamic-import-node "^2.3.0" "@babel/plugin-transform-modules-commonjs@^7.5.0": @@ -1135,11 +1435,19 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-new-target@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" + integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-object-super@^7.0.0": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz#4a0753d2d60639437be07b592a9e58ee00720167" - integrity sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz#48488937a2d586c0148451bf51af9d7dda567262" + integrity sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.7.4" "@babel/plugin-transform-object-super@^7.5.5": version "7.5.5" @@ -1150,12 +1458,21 @@ "@babel/helper-replace-supers" "^7.5.5" "@babel/plugin-transform-object-super@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" + integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.0.0": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz#48488937a2d586c0148451bf51af9d7dda567262" - integrity sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.4.tgz#da4555c97f39b51ac089d31c7380f03bca4075ce" + integrity sha512-VJwhVePWPa0DqE9vcfptaJSzNDKrWU/4FbYCjZERtmqEs05g3UMXnYMZoXja7JAJ7Y7sPZipwm/pGApZt7wHlw== dependencies: + "@babel/helper-call-delegate" "^7.7.4" + "@babel/helper-get-function-arity" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.7.4" "@babel/plugin-transform-parameters@^7.4.4": version "7.4.4" @@ -1167,12 +1484,19 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-parameters@^7.7.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.4.tgz#1d5155de0b65db0ccf9971165745d3bb990d77d3" + integrity sha512-IsS3oTxeTsZlE5KqzTbcC2sV0P9pXdec53SU+Yxv7o/6dvGM5AkTotQKhoSffhNgZ/dftsSiOoxy7evCYJXzVA== + dependencies: + "@babel/helper-call-delegate" "^7.8.3" + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-property-literals@^7.0.0", "@babel/plugin-transform-property-literals@^7.7.4": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.4.tgz#da4555c97f39b51ac089d31c7380f03bca4075ce" - integrity sha512-VJwhVePWPa0DqE9vcfptaJSzNDKrWU/4FbYCjZERtmqEs05g3UMXnYMZoXja7JAJ7Y7sPZipwm/pGApZt7wHlw== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.7.4.tgz#2388d6505ef89b266103f450f9167e6bd73f98c2" + integrity sha512-MatJhlC4iHsIskWYyawl53KuHrt+kALSADLQQ/HkhTjX954fkxIEh4q5slL4oRAnsm/eDoZ4q0CIZpcqBuxhJQ== dependencies: - "@babel/helper-call-delegate" "^7.7.4" - "@babel/helper-get-function-arity" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-property-literals@^7.2.0": @@ -1182,13 +1506,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-property-literals@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.7.4.tgz#2388d6505ef89b266103f450f9167e6bd73f98c2" - integrity sha512-MatJhlC4iHsIskWYyawl53KuHrt+kALSADLQQ/HkhTjX954fkxIEh4q5slL4oRAnsm/eDoZ4q0CIZpcqBuxhJQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-react-constant-elements@^7.0.0", "@babel/plugin-transform-react-constant-elements@^7.2.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.5.0.tgz#4d6ae4033bc38f8a65dfca2b6235c44522a422fc" @@ -1307,6 +1624,13 @@ resolve "^1.8.1" semver "^5.5.1" +"@babel/plugin-transform-shorthand-properties@^7.0.0": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz#74a0a9b2f6d67a684c6fbfd5f0458eb7ba99891e" + integrity sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-shorthand-properties@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" @@ -1315,9 +1639,16 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-shorthand-properties@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" + integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-spread@^7.0.0", "@babel/plugin-transform-spread@^7.7.4": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz#74a0a9b2f6d67a684c6fbfd5f0458eb7ba99891e" - integrity sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz#aa673b356fe6b7e70d69b6e33a17fef641008578" + integrity sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -1328,13 +1659,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-spread@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz#aa673b356fe6b7e70d69b6e33a17fef641008578" - integrity sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-sticky-regex@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" @@ -1344,12 +1668,20 @@ "@babel/helper-regex" "^7.0.0" "@babel/plugin-transform-sticky-regex@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" + integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-regex" "^7.8.3" + +"@babel/plugin-transform-template-literals@^7.0.0", "@babel/plugin-transform-template-literals@^7.7.4": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz#ffb68c05090c30732076b1285dc1401b404a123c" - integrity sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A== + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz#1eb6411736dd3fe87dbd20cc6668e5121c17d604" + integrity sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ== dependencies: + "@babel/helper-annotate-as-pure" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" "@babel/plugin-transform-template-literals@^7.4.4": version "7.4.4" @@ -1359,14 +1691,6 @@ "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-template-literals@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz#1eb6411736dd3fe87dbd20cc6668e5121c17d604" - integrity sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-typeof-symbol@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" @@ -1624,9 +1948,9 @@ "@babel/plugin-transform-typescript" "^7.3.2" "@babel/preset-typescript@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.7.4.tgz#780059a78e6fa7f7a4c87f027292a86b31ce080a" - integrity sha512-rqrjxfdiHPsnuPur0jKrIIGQCIgoTWMTjlbWE69G4QJ6TIOVnnRnIJhUxNTL/VwDmEAVX08Tq3B1nirer5341w== + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.7.7.tgz#69ddea54e8b4e491ccbf94147e673b2ac6e11e2e" + integrity sha512-Apg0sCTovsSA+pEaI8efnA44b9x4X/7z4P8vsWMiN8rSUaM4y4+Shl5NMWnMl6njvt96+CEb6jwpXAKYAVCSQA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-typescript" "^7.7.4" @@ -1721,6 +2045,30 @@ "@babel/parser" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/template@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" + integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/traverse@7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.3.tgz#a826215b011c9b4f73f3a893afbc05151358bf9a" + integrity sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.3" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/types" "^7.8.3" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + "@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.5.tgz#f664f8f368ed32988cd648da9f72d5ca70f165bb" @@ -1736,17 +2084,17 @@ globals "^11.1.0" lodash "^4.17.13" -"@babel/traverse@^7.1.6", "@babel/traverse@^7.6.0": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.6.2.tgz#b0e2bfd401d339ce0e6c05690206d1e11502ce2c" - integrity sha512-8fRE76xNwNttVEF2TwxJDGBLWthUkHWSldmfuBzVRmEDWOtu4XdINTgN7TDWzuLg4bbeIMLvfMFD9we5YcWkRQ== +"@babel/traverse@^7.1.6", "@babel/traverse@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" + integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw== dependencies: "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.6.2" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.4" - "@babel/parser" "^7.6.2" - "@babel/types" "^7.6.0" + "@babel/generator" "^7.7.4" + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/parser" "^7.7.4" + "@babel/types" "^7.7.4" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.13" @@ -1766,21 +2114,45 @@ globals "^11.1.0" lodash "^4.17.13" -"@babel/traverse@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" - integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw== +"@babel/traverse@^7.6.0": + version "7.6.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.6.2.tgz#b0e2bfd401d339ce0e6c05690206d1e11502ce2c" + integrity sha512-8fRE76xNwNttVEF2TwxJDGBLWthUkHWSldmfuBzVRmEDWOtu4XdINTgN7TDWzuLg4bbeIMLvfMFD9we5YcWkRQ== dependencies: "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.7.4" - "@babel/helper-function-name" "^7.7.4" - "@babel/helper-split-export-declaration" "^7.7.4" - "@babel/parser" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/generator" "^7.6.2" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/parser" "^7.6.2" + "@babel/types" "^7.6.0" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.13" +"@babel/traverse@^7.8.3": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.4.tgz#f0845822365f9d5b0e312ed3959d3f827f869e3c" + integrity sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.4" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.8.4" + "@babel/types" "^7.8.3" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@7.8.3", "@babel/types@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" + integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + "@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.5.tgz#97b9f728e182785909aa4ab56264f090a028d18a" @@ -2168,6 +2540,200 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.4.tgz#622a72bebd1e3f48d921563b4b60a762295a81fc" integrity sha512-6PYY5DVdAY1ifaQW6XYTnOMihmBVT27elqSjEoodchsGjzYlEsTQMcEhSud99kVawatyTZRTiVkJ/c6lwbQ7nA== +"@graphql-codegen/add@^1.12.2": + version "1.12.2" + resolved "https://registry.yarnpkg.com/@graphql-codegen/add/-/add-1.12.2.tgz#d018f307520525bfbb59fde0d0ecca0b53714212" + integrity sha512-r4O3aXsi8gwm1v27C3T00HnPdn1mZzmp7ZfeEcsG8KymrVgHwh2VUPIevXRr0G6qPu8AnyqxBGWGm+mZme9Eag== + dependencies: + "@graphql-codegen/plugin-helpers" "1.12.2" + tslib "1.10.0" + +"@graphql-codegen/core@^1.12.2": + version "1.12.2" + resolved "https://registry.yarnpkg.com/@graphql-codegen/core/-/core-1.12.2.tgz#85dcef3a9205f11aa910f0527c272967ed5c4427" + integrity sha512-n7OENe0lXIg40AGokO0W5v/OKo+bd4gjdKCRVp8N9Pu0o0uYm11rtCoL1JESJqUSt/LESbq+FH14fUqdXU048Q== + dependencies: + "@graphql-codegen/plugin-helpers" "1.12.2" + "@graphql-toolkit/common" "0.9.7" + "@graphql-toolkit/schema-merging" "0.9.7" + tslib "1.10.0" + +"@graphql-codegen/plugin-helpers@1.12.2": + version "1.12.2" + resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-1.12.2.tgz#44ffeefb21515b021f99c6e5be28699d740af560" + integrity sha512-N294rqdBh+mCi4HWHbhPV9wE0XLCVKx524pYL4yp8qWiSdAs3Iz9+q9C9QNsLBvHypZdqml44M8kBMG41A9I/Q== + dependencies: + "@graphql-toolkit/common" "0.9.7" + camel-case "4.1.1" + common-tags "1.8.0" + constant-case "3.0.3" + import-from "3.0.0" + lower-case "2.0.1" + param-case "3.0.3" + pascal-case "3.1.1" + tslib "1.10.0" + upper-case "2.0.1" + +"@graphql-codegen/typescript-compatibility@^1.12.2": + version "1.12.2" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-compatibility/-/typescript-compatibility-1.12.2.tgz#3dce0545acaab072b4069134b32954bca5e0cba1" + integrity sha512-DK2ovG9fcoUqkOiCCXFZ5E32eakcrbH+em8NIP2WEtB9hhk1FL0NEockpacaRAXvuqOqxygMYR24GWNssvdFKw== + dependencies: + "@graphql-codegen/plugin-helpers" "1.12.2" + "@graphql-codegen/visitor-plugin-common" "1.12.2" + pascal-case "3.1.1" + tslib "1.10.0" + +"@graphql-codegen/typescript-operations@^1.12.2": + version "1.12.2" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-operations/-/typescript-operations-1.12.2.tgz#d5d495f237b1bb93839e28da0ddecc5f4ce9f877" + integrity sha512-U4wp9H5sbCP3kWEXI5SbGYeXUyDKidHi2kBRoQochEdsTXugF+6dr5WuUY3IvLIYS9qNKHKq6dm/9nl3DpBD+Q== + dependencies: + "@graphql-codegen/plugin-helpers" "1.12.2" + "@graphql-codegen/typescript" "1.12.2" + "@graphql-codegen/visitor-plugin-common" "1.12.2" + auto-bind "4.0.0" + tslib "1.10.0" + +"@graphql-codegen/typescript-react-apollo@^1.12.2": + version "1.12.2" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-react-apollo/-/typescript-react-apollo-1.12.2.tgz#6a25bd07550ea795c023c98bffcf8a57b1240a33" + integrity sha512-oMRRmHTtd8LdAG8FN7msp7O9T960Oxm04L2JNYDoWc1GuxcMXo3ZVR7bRGgcvgDSmV391k5PSCtA3B8T/QgXjA== + dependencies: + "@graphql-codegen/plugin-helpers" "1.12.2" + "@graphql-codegen/visitor-plugin-common" "1.12.2" + auto-bind "4.0.0" + camel-case "4.1.1" + pascal-case "3.1.1" + tslib "1.10.0" + +"@graphql-codegen/typescript-resolvers@^1.12.2": + version "1.12.2" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-resolvers/-/typescript-resolvers-1.12.2.tgz#17ed56be4d249ce961f5e6135d1c1ba5461ccfe9" + integrity sha512-+YJIAMck3X4DPC4Bwt8Ht4mlHxdYzMemHtRZjur0V6+WnxMxjE1NDylZ0bynhbbHd6bM1yoA3JpU5jCBcxF1Gw== + dependencies: + "@graphql-codegen/plugin-helpers" "1.12.2" + "@graphql-codegen/typescript" "1.12.2" + "@graphql-codegen/visitor-plugin-common" "1.12.2" + "@graphql-toolkit/common" "0.9.7" + auto-bind "4.0.0" + tslib "1.10.0" + +"@graphql-codegen/typescript@1.12.2", "@graphql-codegen/typescript@^1.12.2": + version "1.12.2" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript/-/typescript-1.12.2.tgz#4b63ab80dcac7624711459e776201c6a5d0f7373" + integrity sha512-G2H91ocAEcZ86TFNQWV2HZUdXSR7v/Ntjq0ChqDvz/a7PTJxa5Pe5j4sQ9q13vGR5CedAMbBZkZ8zTKLAqY5sg== + dependencies: + "@graphql-codegen/plugin-helpers" "1.12.2" + "@graphql-codegen/visitor-plugin-common" "1.12.2" + auto-bind "4.0.0" + tslib "1.10.0" + +"@graphql-codegen/visitor-plugin-common@1.12.2": + version "1.12.2" + resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-1.12.2.tgz#a32ed6ed2554bd2df125675e296d110d7ec00420" + integrity sha512-+DOnCNvgsMvVVXgAqA2Kqvcy9g0V5xiMAmpgNfrRE1tJ2PGXFsYP4HElBu+PQZCTn5AR8Tfw037zhfbUuF5oDw== + dependencies: + "@graphql-codegen/plugin-helpers" "1.12.2" + "@graphql-toolkit/relay-operation-optimizer" "0.9.7" + auto-bind "4.0.0" + dependency-graph "0.8.1" + graphql-tag "2.10.1" + pascal-case "3.1.1" + tslib "1.10.0" + +"@graphql-toolkit/code-file-loader@^0.9.7": + version "0.9.7" + resolved "https://registry.yarnpkg.com/@graphql-toolkit/code-file-loader/-/code-file-loader-0.9.7.tgz#3a1ee8dfd8029dbfba1ee4178dca1cbe3c313e04" + integrity sha512-Vs2E7ojJ2gmhTz+U0MRLMib8yPz4+U1THCE3QgP4Pqnrqnkp/kEI7qpt3G3XI7JRRBWDHU2gdwOydnHmM/Cjow== + dependencies: + "@graphql-toolkit/common" "0.9.7" + "@graphql-toolkit/graphql-tag-pluck" "0.9.7" + tslib "1.10.0" + +"@graphql-toolkit/common@0.9.7", "@graphql-toolkit/common@^0.9.7": + version "0.9.7" + resolved "https://registry.yarnpkg.com/@graphql-toolkit/common/-/common-0.9.7.tgz#63bc6233c4fd88bc94dfe6a3ec85b8f961f780f9" + integrity sha512-dpSRBMLeIiRct2gkjj24bp0EV7hbK/7dpJAPqNgvDH2535LhOkprYiCXQJyP4N1LODAEkpN/zzlJfKMVn773MQ== + dependencies: + "@ardatan/graphql-tools" "4.1.0" + aggregate-error "3.0.1" + lodash "4.17.15" + +"@graphql-toolkit/core@^0.9.7": + version "0.9.7" + resolved "https://registry.yarnpkg.com/@graphql-toolkit/core/-/core-0.9.7.tgz#a68fff000f3aedb6584c22f3f6b641885aec0f56" + integrity sha512-w1WU0iOq6AEBTICDxcu1xjFruFfGCHg6ERdWTWdIBOTn30qysIC0ek+XWN67vF9yV9QIdAxNu66gXKjUUWm2Tg== + dependencies: + "@graphql-toolkit/common" "0.9.7" + "@graphql-toolkit/schema-merging" "0.9.7" + aggregate-error "3.0.1" + globby "11.0.0" + import-from "^3.0.0" + is-glob "4.0.1" + lodash "4.17.15" + resolve-from "5.0.0" + tslib "1.10.0" + unixify "1.0.0" + valid-url "1.0.9" + +"@graphql-toolkit/graphql-file-loader@^0.9.7": + version "0.9.7" + resolved "https://registry.yarnpkg.com/@graphql-toolkit/graphql-file-loader/-/graphql-file-loader-0.9.7.tgz#1f15dfcf50342ab9e480fbbe2b16896395f36c45" + integrity sha512-t7CfYjghuXAtIqzwHhkUoE/u0a918UTOOVtHdLHh8rojjIUfsSeLeqMcFacRv+/z+kyKl9lgi4TE/qiyIpyR5A== + dependencies: + "@graphql-toolkit/common" "0.9.7" + tslib "1.10.0" + +"@graphql-toolkit/graphql-tag-pluck@0.9.7": + version "0.9.7" + resolved "https://registry.yarnpkg.com/@graphql-toolkit/graphql-tag-pluck/-/graphql-tag-pluck-0.9.7.tgz#772c5f15fb9b8e5f61d2816c4cfb1dcd1e3ba34e" + integrity sha512-hfHs9m/6rK0JRPrZg9LW8fPmQiNy7zvueey+TUH+qLHOkQiklDVDtQ/2yje35B16bwiyk3axxmHZ/H3fb5nWiQ== + dependencies: + "@babel/parser" "7.8.3" + "@babel/traverse" "7.8.3" + "@babel/types" "7.8.3" + "@graphql-toolkit/common" "0.9.7" + optionalDependencies: + vue-template-compiler "^2.6.11" + +"@graphql-toolkit/json-file-loader@^0.9.7": + version "0.9.7" + resolved "https://registry.yarnpkg.com/@graphql-toolkit/json-file-loader/-/json-file-loader-0.9.7.tgz#3f68dfbbc0c55c2b1531b6e200d5cd76ef85bb59" + integrity sha512-MNnCX201p011FPOm/rlDLkBTpx4LvooG9pdMU1ijRD/sqpHSkhZ2U/aKyoiDDKrLUgK7cvHws1KXBvLcg7r6aQ== + dependencies: + "@graphql-toolkit/common" "0.9.7" + tslib "1.10.0" + +"@graphql-toolkit/relay-operation-optimizer@0.9.7": + version "0.9.7" + resolved "https://registry.yarnpkg.com/@graphql-toolkit/relay-operation-optimizer/-/relay-operation-optimizer-0.9.7.tgz#e13034f835231b268ee355bfac6228dd34f9b951" + integrity sha512-IPFAbKMOX3RdjyDuamK9ziuTFD5tsCiTVvHACHA2wgg+32krJZJsV6STKhFLqIwytS40vt5zhZydQCFxIrCD5g== + dependencies: + "@graphql-toolkit/common" "0.9.7" + relay-compiler "8.0.0" + +"@graphql-toolkit/schema-merging@0.9.7", "@graphql-toolkit/schema-merging@^0.9.7": + version "0.9.7" + resolved "https://registry.yarnpkg.com/@graphql-toolkit/schema-merging/-/schema-merging-0.9.7.tgz#241ddd2c9ba79dd4444014057d0765777ab3cd12" + integrity sha512-RLhP0+XT4JGoPGCvlcTPdCE8stA7l0D5+gZ8ZP0snqzZOdsDFG4cNxpJtwf48i7uArsXkfu5OjOvTwh0MR0Wrw== + dependencies: + "@ardatan/graphql-tools" "4.1.0" + "@graphql-toolkit/common" "0.9.7" + deepmerge "4.2.2" + tslib "1.10.0" + +"@graphql-toolkit/url-loader@^0.9.7": + version "0.9.7" + resolved "https://registry.yarnpkg.com/@graphql-toolkit/url-loader/-/url-loader-0.9.7.tgz#222af4f8bb6d87735760555dd100c55fd3d36281" + integrity sha512-cOT2XJVZLWOKG4V9ucVtUTqJMW0BJqEqrHvpR8YcIWffrEChmzZQX+ug3BkRNomaUe8ywgExJ80aZuKWeSHvew== + dependencies: + "@ardatan/graphql-tools" "4.1.0" + "@graphql-toolkit/common" "0.9.7" + cross-fetch "3.0.4" + tslib "1.10.0" + valid-url "1.0.9" + "@gulp-sourcemaps/identity-map@1.X": version "1.0.2" resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz#1e6fe5d8027b1f285dc0d31762f566bccd73d5a9" @@ -2655,6 +3221,17 @@ dependencies: core-js "^2.5.7" +"@kamilkisiela/graphql-tools@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@kamilkisiela/graphql-tools/-/graphql-tools-4.0.6.tgz#6dcf4d18bedaf34f6ab1d5bad2414e530d0875d1" + integrity sha512-IPWa+dOFCE4zaCsrJrAMp7yWXnfOZLNhqoMEOmn958WkLM0mmsDc/W/Rh7/7xopIT6P0oizb6/N1iH5HnNXOUA== + dependencies: + apollo-link "^1.2.3" + apollo-utilities "^1.0.1" + deprecated-decorator "^0.1.6" + iterall "^1.1.3" + uuid "^3.1.0" + "@mapbox/extent@0.4.0": version "0.4.0" resolved "https://registry.yarnpkg.com/@mapbox/extent/-/extent-0.4.0.tgz#3e591f32e1f0c3981c864239f7b0ac06e610f8a9" @@ -2847,38 +3424,25 @@ resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.14.tgz#0e0810a0a174e50e22dfe8edb30599840712f22d" integrity sha512-518yewjSga1jLdiLrcmpMFlaba5P+50b0TWNFUpC+SL9Yzf0kMi57qw+bMl+rQ08cGqH1vLx4eg9YFUbZXgZ0Q== -"@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" - -"@nodelib/fs.scandir@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.1.tgz#7fa8fed654939e1a39753d286b48b4836d00e0eb" - integrity sha512-NT/skIZjgotDSiXs0WqYhgcuBKhUMgfekCmCGtkUAiLqZdOnrdjmZr9wRl3ll64J9NF79uZ4fk16Dx0yMc/Xbg== +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== dependencies: - "@nodelib/fs.stat" "2.0.1" + "@nodelib/fs.stat" "2.0.3" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.1", "@nodelib/fs.stat@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.1.tgz#814f71b1167390cfcb6a6b3d9cdeb0951a192c14" - integrity sha512-+RqhBlLn6YRBGOIoVYthsG0J9dfpO79eJyN7BYBkZJtfqrBwf2KK+rD/M/yjZR6WBmIhAgOV7S60eCgaSWtbFw== - -"@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== -"@nodelib/fs.walk@^1.2.1": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.2.tgz#6a6450c5e17012abd81450eb74949a4d970d2807" - integrity sha512-J/DR3+W12uCzAJkw7niXDcqcKBg6+5G5Q/ZpThpGNzAUz70eOR6RV4XnnSN01qHZiVl0eavoxJsBypQoKsV2QQ== +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== dependencies: - "@nodelib/fs.scandir" "2.1.1" + "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" "@oclif/color@^0.0.0": @@ -4120,11 +4684,6 @@ resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.33.tgz#2728669427cdd74a99e53c9f457ca2866a37c52d" integrity sha512-VQgHxyPMTj3hIlq9SY1mctqx+Jj8kpQfoLvDlVSDNOyuYs8JYfkuY3OW/4+dO657yPmNhHpePRx0/Tje5ImNVQ== -"@types/async@2.0.49": - version "2.0.49" - resolved "https://registry.yarnpkg.com/@types/async/-/async-2.0.49.tgz#92e33d13f74c895cb9a7f38ba97db8431ed14bc0" - integrity sha512-Benr3i5odUkvpFkOpzGqrltGdbSs+EVCkEBGXbuR7uT0VzhXKIkhem6PDzHdx5EonA+rfbB3QvP6aDOw5+zp5Q== - "@types/babel-types@*", "@types/babel-types@^7.0.0": version "7.0.4" resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.4.tgz#bfd5b0d0d1ba13e351dff65b6e52783b816826c8" @@ -4297,9 +4856,11 @@ integrity sha512-EIjmpvnHj+T4nMcKwHwxZKUfDmphIKJc2qnEMhSoOvr1lYEQpuRKRz8orWr//krYIIArS/KGGLfL2YGVUYXmIA== "@types/cp-file@*": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@types/cp-file/-/cp-file-4.2.0.tgz#2b12186b50dad407b11021284627bdf4adb87a87" - integrity sha512-nkd9c0L2aWfsDFrkpxfGJ5bCKeiAv6lccbH9vxKeWYw9YuyqskjtRTrBEBAiea9R08OSiboQ4ssmwAVJMHmHHA== + version "6.1.2" + resolved "https://registry.yarnpkg.com/@types/cp-file/-/cp-file-6.1.2.tgz#3c579201715ca6177d34f3e14f2b29861c470c4c" + integrity sha512-wvqCNhHt+GMfEglZ83cQ+8dEv5Oh8DwEq6IBBBL7+hWISR+82l/bSmssCo5zGHg7HpW6+kjZwDby9zGkCStN5w== + dependencies: + cp-file "*" "@types/cpy@^5.1.0": version "5.1.0" @@ -4499,11 +5060,6 @@ dependencies: "@types/node" "*" -"@types/graphql@^0.13.2": - version "0.13.4" - resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.13.4.tgz#55ae9c29f0fd6b85ee536f5c72b4769d5c5e06b1" - integrity sha512-B4yel4ro2nTb3v0pYO8vO6SjgvFJSrwUY+IO6TUSLdOSB+gQFslylrhRCHxvXMIhxB71mv5PEE9dAX+24S8sew== - "@types/gulp@^4.0.6": version "4.0.6" resolved "https://registry.yarnpkg.com/@types/gulp/-/gulp-4.0.6.tgz#68fe0e1f0ff3657cfca46fb564806b744a1bf899" @@ -5694,7 +6250,14 @@ "@types/node" "^12.0.2" tslib "^1.9.3" -"@wry/equality@^0.1.2": +"@wry/context@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.5.0.tgz#5ff84d0d5726b62c07045af8465f890eb3823c8c" + integrity sha512-yW5XFrWbRvv2/f86+g0YAfko7671SQg7Epn8lYjux4MZmIvtPvK2ts+vG1QAPu2w6GuBioEJknRa7K2LFj2kQw== + dependencies: + tslib "^1.9.3" + +"@wry/equality@^0.1.2", "@wry/equality@^0.1.9": version "0.1.9" resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.9.tgz#b13e18b7a8053c6858aa6c85b54911fb31e3a909" integrity sha512-mB6ceGjpMGz1ZTza8HYnrPGos2mC6So4NhS1PtZ8s4Qt0K7fBiIGhpSxUbQmhwcSWE3no+bYxmI2OL6KuXYmoQ== @@ -5958,6 +6521,14 @@ aggregate-error@2.1.0: clean-stack "^2.0.0" indent-string "^3.0.0" +aggregate-error@3.0.1, aggregate-error@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" + integrity sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + aggregate-error@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-1.0.0.tgz#888344dad0220a72e3af50906117f48771925fac" @@ -5966,14 +6537,6 @@ aggregate-error@^1.0.0: clean-stack "^1.0.0" indent-string "^3.0.0" -aggregate-error@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" - integrity sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - "airbnb-js-shims@^1 || ^2": version "2.1.1" resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-2.1.1.tgz#a509611480db7e6d9db62fe2acfaeb473b6842ac" @@ -6293,7 +6856,7 @@ ansi-styles@^3.2.0: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-styles@^4.0.0: version "4.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== @@ -6301,6 +6864,14 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" +ansi-styles@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.0.tgz#5681f0dcf7ae5880a7841d8831c4724ed9cc0172" + integrity sha512-7kFQgnEaMdRtwf6uSfUnVr9gSGC7faurn+J/Mv90/W+iTtN0405/nLdopfMWwchyxhbGYl6TC4Sccn9TUkGAgg== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + ansi-styles@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" @@ -6377,59 +6948,34 @@ apollo-cache-inmemory@1.6.2: ts-invariant "^0.4.0" tslib "^1.9.3" -apollo-cache@^1.1.14: - version "1.1.14" - resolved "https://registry.yarnpkg.com/apollo-cache/-/apollo-cache-1.1.14.tgz#c7d54cdbc7f544161f78fa5e4bae56650e22f7ad" - integrity sha512-Zmo9nVqpWFogki2QyulX6Xx6KYXMyYWX74grwgsYYUOukl4pIAdtYyK8e874o0QDgzSOq5AYPXjtfkoVpqhCRw== - dependencies: - apollo-utilities "^1.0.18" - -apollo-cache@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/apollo-cache/-/apollo-cache-1.3.2.tgz#df4dce56240d6c95c613510d7e409f7214e6d26a" - integrity sha512-+KA685AV5ETEJfjZuviRTEImGA11uNBp/MJGnaCvkgr+BYRrGLruVKBv6WvyFod27WEB2sp7SsG8cNBKANhGLg== +apollo-cache@1.3.4, apollo-cache@^1.3.2: + version "1.3.4" + resolved "https://registry.yarnpkg.com/apollo-cache/-/apollo-cache-1.3.4.tgz#0c9f63c793e1cd6e34c450f7668e77aff58c9a42" + integrity sha512-7X5aGbqaOWYG+SSkCzJNHTz2ZKDcyRwtmvW4mGVLRqdQs+HxfXS4dUS2CcwrAj449se6tZ6NLUMnjko4KMt3KA== dependencies: - apollo-utilities "^1.3.2" - tslib "^1.9.3" + apollo-utilities "^1.3.3" + tslib "^1.10.0" apollo-client@^2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.3.8.tgz#0384a7210eb601ab88b1c13750da076fc9255b95" - integrity sha512-X5wsBD1be1P/mScGsH5H+2hIE8d78WAfqOvFvBpP+C+jzJ9387uHLyFmYYMLRRqDQ3ihjI4iSID7KEOW2gyCcQ== + version "2.6.8" + resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.6.8.tgz#01cebc18692abf90c6b3806414e081696b0fa537" + integrity sha512-0zvJtAcONiozpa5z5zgou83iEKkBaXhhSSXJebFHRXs100SecDojyUWKjwTtBPn9HbM6o5xrvC5mo9VQ5fgAjw== dependencies: "@types/zen-observable" "^0.8.0" - apollo-cache "^1.1.14" + apollo-cache "1.3.4" apollo-link "^1.0.0" - apollo-link-dedup "^1.0.0" - apollo-utilities "^1.0.18" + apollo-utilities "1.3.3" symbol-observable "^1.0.2" + ts-invariant "^0.4.0" + tslib "^1.10.0" zen-observable "^0.8.0" - optionalDependencies: - "@types/async" "2.0.49" -apollo-link-dedup@^1.0.0: - version "1.0.9" - resolved "https://registry.yarnpkg.com/apollo-link-dedup/-/apollo-link-dedup-1.0.9.tgz#3c4e4af88ef027cbddfdb857c043fd0574051dad" - integrity sha512-RbuEKpmSHVMtoREMPh2wUFTeh65q+0XPVeqgaOP/rGEAfvLyOMvX0vT2nVaejMohoMxuUnfZwpldXaDFWnlVbg== +apollo-link-error@^2.0.0-beta.0: + version "2.0.0-beta.0" + resolved "https://registry.yarnpkg.com/apollo-link-error/-/apollo-link-error-2.0.0-beta.0.tgz#58a06f0bc8658abe3490cb6fa7ed0f6d6c10cf98" + integrity sha512-eoTy/PG2JG+co+yOuLoTrk7PFiiIRDByrBytnAI/WGk67ez8px1wKsq3/EoPjAL+ty2IxgET+blu7zqQogEJwA== dependencies: - apollo-link "^1.2.2" - -apollo-link-error@^1.1.7: - version "1.1.10" - resolved "https://registry.yarnpkg.com/apollo-link-error/-/apollo-link-error-1.1.10.tgz#ce57f0793f0923b598655de5bf5e028d4cf4fba6" - integrity sha512-itG5UV7mQqaalmRkuRsF0cUS4zW2ja8XCbxkMZnIEeN24X3yoJi5hpJeAaEkXf0KgYNsR0+rmtCQNruWyxDnZQ== - dependencies: - apollo-link "^1.2.11" - apollo-link-http-common "^0.2.13" - tslib "^1.9.3" - -apollo-link-http-common@^0.2.13: - version "0.2.13" - resolved "https://registry.yarnpkg.com/apollo-link-http-common/-/apollo-link-http-common-0.2.13.tgz#c688f6baaffdc7b269b2db7ae89dae7c58b5b350" - integrity sha512-Uyg1ECQpTTA691Fwx5e6Rc/6CPSu4TB4pQRTGIpwZ4l5JDOQ+812Wvi/e3IInmzOZpwx5YrrOfXrtN8BrsDXoA== - dependencies: - apollo-link "^1.2.11" - ts-invariant "^0.3.2" + "@apollo/client" "^3.0.0-beta.10" tslib "^1.9.3" apollo-link-http-common@^0.2.15: @@ -6458,32 +7004,14 @@ apollo-link-schema@^1.1.0: apollo-link "^1.2.2" apollo-link-state@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/apollo-link-state/-/apollo-link-state-0.4.1.tgz#65e9e0e12c67936b8c4b12b8438434f393104579" - integrity sha512-69/til4ENfl/Fvf7br2xSsLSBcxcXPbOHVNkzLLejvUZickl93HLO4/fO+uvoBi4dCYRgN17Zr8FwI41ueRx0g== + version "0.4.2" + resolved "https://registry.yarnpkg.com/apollo-link-state/-/apollo-link-state-0.4.2.tgz#ac00e9be9b0ca89eae0be6ba31fe904b80bbe2e8" + integrity sha512-xMPcAfuiPVYXaLwC6oJFIZrKgV3GmdO31Ag2eufRoXpvT0AfJZjdaPB4450Nu9TslHRePN9A3quxNueILlQxlw== dependencies: apollo-utilities "^1.0.8" graphql-anywhere "^4.1.0-alpha.0" -apollo-link@^1.0.0, apollo-link@^1.2.2, apollo-link@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.3.tgz#9bd8d5fe1d88d31dc91dae9ecc22474d451fb70d" - integrity sha512-iL9yS2OfxYhigme5bpTbmRyC+Htt6tyo2fRMHT3K1XRL/C5IQDDz37OjpPy4ndx7WInSvfSZaaOTKFja9VWqSw== - dependencies: - apollo-utilities "^1.0.0" - zen-observable-ts "^0.8.10" - -apollo-link@^1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.11.tgz#493293b747ad3237114ccd22e9f559e5e24a194d" - integrity sha512-PQvRCg13VduLy3X/0L79M6uOpTh5iHdxnxYuo8yL7sJlWybKRJwsv4IcRBJpMFbChOOaHY7Og9wgPo6DLKDKDA== - dependencies: - apollo-utilities "^1.2.1" - ts-invariant "^0.3.2" - tslib "^1.9.3" - zen-observable-ts "^0.8.18" - -apollo-link@^1.2.13: +apollo-link@^1.0.0, apollo-link@^1.2.13, apollo-link@^1.2.2, apollo-link@^1.2.3: version "1.2.13" resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.13.tgz#dff00fbf19dfcd90fddbc14b6a3f9a771acac6c4" integrity sha512-+iBMcYeevMm1JpYgwDEIDt/y0BB7VWyvlm/7x+TIPNLHCTCMgcEgDuW5kH86iQZWo0I7mNwQiTOz+/3ShPFmBw== @@ -6493,10 +7021,10 @@ apollo-link@^1.2.13: tslib "^1.9.3" zen-observable-ts "^0.8.20" -apollo-server-core@^1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-1.3.6.tgz#08636243c2de56fa8c267d68dd602cb1fbd323e3" - integrity sha1-CGNiQ8LeVvqMJn1o3WAssfvTI+M= +apollo-server-core@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-1.4.0.tgz#4faff7f110bfdd6c3f47008302ae24140f94c592" + integrity sha512-BP1Vh39krgEjkQxbjTdBURUjLHbFq1zeOChDJgaRsMxGtlhzuLWwwC6lLdPatN8jEPbeHq8Tndp9QZ3iQZOKKA== dependencies: apollo-cache-control "^0.1.0" apollo-tracing "^0.1.0" @@ -6508,18 +7036,18 @@ apollo-server-errors@^2.0.2: integrity sha512-zyWDqAVDCkj9espVsoUpZr9PwDznM8UW6fBfhV+i1br//s2AQb07N6ektZ9pRIEvkhykDZW+8tQbDwAO0vUROg== apollo-server-hapi@^1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/apollo-server-hapi/-/apollo-server-hapi-1.3.6.tgz#44dea128b64c1c10fdd35ac8307896a57ba1f4a8" - integrity sha1-RN6hKLZMHBD901rIMHiWpXuh9Kg= + version "1.4.0" + resolved "https://registry.yarnpkg.com/apollo-server-hapi/-/apollo-server-hapi-1.4.0.tgz#df63dcac17120490cde756370bdb5ea965141bc3" + integrity sha512-wChLPugWVcJM6gcSUuoHV6rO5pJUMrjkO5KcvPy4JXgpAbIGewpQvqJO8mk1y3C48WEhTOlgiFPquzGTnk6yFg== dependencies: - apollo-server-core "^1.3.6" - apollo-server-module-graphiql "^1.3.4" + apollo-server-core "^1.4.0" + apollo-server-module-graphiql "^1.4.0" boom "^7.1.0" -apollo-server-module-graphiql@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/apollo-server-module-graphiql/-/apollo-server-module-graphiql-1.3.4.tgz#50399b7c51b7267d0c841529f5173e5fc7304de4" - integrity sha1-UDmbfFG3Jn0MhBUp9Rc+X8cwTeQ= +apollo-server-module-graphiql@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/apollo-server-module-graphiql/-/apollo-server-module-graphiql-1.4.0.tgz#c559efa285578820709f1769bb85d3b3eed3d8ec" + integrity sha512-GmkOcb5he2x5gat+TuiTvabnBf1m4jzdecal3XbXBh/Jg+kx4hcvO3TTDFQ9CuTprtzdcVyA11iqG7iOMOt7vA== apollo-tracing@^0.1.0: version "0.1.4" @@ -6528,23 +7056,17 @@ apollo-tracing@^0.1.0: dependencies: graphql-extensions "~0.0.9" -apollo-utilities@^1.0.0, apollo-utilities@^1.0.1, apollo-utilities@^1.0.18, apollo-utilities@^1.0.8: - version "1.0.18" - resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.0.18.tgz#e4ee91534283fde2b744a26caaea120fe6a94f67" - integrity sha512-hHrmsoMYzzzfUlTOPpxr0qRpTLotMkBIQ93Ub7ki2SWdLfYYKrp6/KB8YOUkbCwXxSFvYSV24ccuwUEqZIaHIA== - dependencies: - fast-json-stable-stringify "^2.0.0" - -apollo-utilities@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.2.1.tgz#1c3a1ebf5607d7c8efe7636daaf58e7463b41b3c" - integrity sha512-Zv8Udp9XTSFiN8oyXOjf6PMHepD4yxxReLsl6dPUy5Ths7jti3nmlBzZUOxuTWRwZn0MoclqL7RQ5UEJN8MAxg== +apollo-utilities@1.3.3, apollo-utilities@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.3.3.tgz#f1854715a7be80cd810bc3ac95df085815c0787c" + integrity sha512-F14aX2R/fKNYMvhuP2t9GD9fggID7zp5I96MF5QeKYWDWTrkRdHRp4+SVfXUVN+cXOaB/IebfvRtzPf25CM0zw== dependencies: + "@wry/equality" "^0.1.2" fast-json-stable-stringify "^2.0.0" - ts-invariant "^0.2.1" - tslib "^1.9.3" + ts-invariant "^0.4.0" + tslib "^1.10.0" -apollo-utilities@^1.3.0, apollo-utilities@^1.3.2: +apollo-utilities@^1.0.1, apollo-utilities@^1.0.8, apollo-utilities@^1.3.0, apollo-utilities@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.3.2.tgz#8cbdcf8b012f664cd6cb5767f6130f5aed9115c9" integrity sha512-JWNHj8XChz7S4OZghV6yc9FNnzEXj285QYp/nLNh943iObycI5GTDO3NGR9Dth12LRrSFMeDOConPfPln+WGfg== @@ -7078,6 +7600,11 @@ attr-accept@^1.1.3: dependencies: core-js "^2.5.0" +auto-bind@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb" + integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ== + autobind-decorator@^1.3.4: version "1.4.3" resolved "https://registry.yarnpkg.com/autobind-decorator/-/autobind-decorator-1.4.3.tgz#4c96ffa77b10622ede24f110f5dbbf56691417d1" @@ -7471,10 +7998,15 @@ babel-plugin-syntax-jsx@^6.18.0: resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= +babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: + version "7.0.0-beta.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" + integrity sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ== + babel-plugin-transform-define@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-define/-/babel-plugin-transform-define-1.3.1.tgz#b21b7bad3b84cf8e3f07cdc8c660b99cbbc01213" - integrity sha512-JXZ1xE9jIbKCGYZ4wbSMPSI5mdS4DRLi5+SkTHgZqWn5YIf/EucykkzUsPmzJlpkX8fsMVdLnA5vt/LvT97Zbg== + version "1.3.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-define/-/babel-plugin-transform-define-1.3.2.tgz#4bdbfe35a839fc206e0f60a7a9ae3b82d5e11808" + integrity sha512-fieU/nFuZjTxIttXoucN1fOIrej8I989IXqATMvKVcgTnfi53BjEwLzkw2KA6Q4gRRl4Cf3iiRVpwiB4PHFuWA== dependencies: lodash "^4.17.11" traverse "0.6.6" @@ -7552,6 +8084,39 @@ babel-polyfill@^6.26.0: core-js "^2.5.0" regenerator-runtime "^0.10.5" +babel-preset-fbjs@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.3.0.tgz#a6024764ea86c8e06a22d794ca8b69534d263541" + integrity sha512-7QTLTCd2gwB2qGoi5epSULMHugSVgpcVt5YAeiFO9ABLrutDQzKfGwzxgZHLpugq8qMdg/DhRZDZ5CLKxBkEbw== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-syntax-class-properties" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-block-scoped-functions" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-for-of" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.0.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-member-expression-literals" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/plugin-transform-object-super" "^7.0.0" + "@babel/plugin-transform-parameters" "^7.0.0" + "@babel/plugin-transform-property-literals" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + babel-plugin-syntax-trailing-function-commas "^7.0.0-beta.0" + babel-preset-jest@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz#192b521e2217fb1d1f67cf73f70c336650ad3cdc" @@ -8109,7 +8674,7 @@ braces@^0.1.2: dependencies: expand-range "^0.1.0" -braces@^2.3.0, braces@^2.3.1, braces@^2.3.2: +braces@^2.3.1, braces@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== @@ -8563,11 +9128,6 @@ caching-transform@^3.0.2: package-hash "^3.0.0" write-file-atomic "^2.4.2" -call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - call@5.x.x: version "5.0.1" resolved "https://registry.yarnpkg.com/call/-/call-5.0.1.tgz#ac1b5c106d9edc2a17af2a4a4f74dd4f0c06e910" @@ -8637,6 +9197,14 @@ camel-case@3.0.x, camel-case@^3.0.0: no-case "^2.2.0" upper-case "^1.1.1" +camel-case@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.1.tgz#1fc41c854f00e2f7d0139dfeba1542d6896fe547" + integrity sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q== + dependencies: + pascal-case "^3.1.1" + tslib "^1.10.0" + camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" @@ -9850,6 +10418,15 @@ const-pinf-float64@^1.0.0: resolved "https://registry.yarnpkg.com/const-pinf-float64/-/const-pinf-float64-1.0.0.tgz#f6efb0d79f9c0986d3e79f2923abf9b70b63d726" integrity sha1-9u+w15+cCYbT558pI6v5twtj1yY= +constant-case@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.3.tgz#ac910a99caf3926ac5112f352e3af599d8c5fc0a" + integrity sha512-FXtsSnnrFYpzDmvwDGQW+l8XK3GV1coLyBN0eBz16ZUzGaZcT2ANVCJmLeuw2GQgxKHQIe9e0w2dzkSfaRlUmA== + dependencies: + no-case "^3.0.3" + tslib "^1.10.0" + upper-case "^2.0.1" + constant-case@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-2.0.0.tgz#4175764d389d3fa9c8ecd29186ed6005243b6a46" @@ -10079,11 +10656,16 @@ core-js@^1.0.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= -core-js@^2.2.0, core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.1, core-js@^2.5.3, core-js@^2.5.7, core-js@^2.6.5, core-js@^2.6.9: +core-js@^2.2.0, core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.1, core-js@^2.5.7, core-js@^2.6.5, core-js@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== +core-js@^2.4.1, core-js@^2.5.3: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== + core-js@^3.0.1, core-js@^3.0.4, core-js@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.2.1.tgz#cd41f38534da6cc59f7db050fe67307de9868b09" @@ -10140,6 +10722,16 @@ cosmiconfig@^5.2.0: js-yaml "^3.13.1" parse-json "^4.0.0" +cp-file@*, cp-file@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-7.0.0.tgz#b9454cfd07fe3b974ab9ea0e5f29655791a9b8cd" + integrity sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw== + dependencies: + graceful-fs "^4.1.2" + make-dir "^3.0.0" + nested-error-stacks "^2.0.0" + p-event "^4.1.0" + cp-file@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-6.2.0.tgz#40d5ea4a1def2a9acdd07ba5c0b0246ef73dc10d" @@ -10151,16 +10743,6 @@ cp-file@^6.2.0: pify "^4.0.1" safe-buffer "^5.0.1" -cp-file@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-7.0.0.tgz#b9454cfd07fe3b974ab9ea0e5f29655791a9b8cd" - integrity sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw== - dependencies: - graceful-fs "^4.1.2" - make-dir "^3.0.0" - nested-error-stacks "^2.0.0" - p-event "^4.1.0" - cpy@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/cpy/-/cpy-8.0.0.tgz#8195db0db19a9ea6aa4f229784cbf3e3f53c3158" @@ -10293,6 +10875,14 @@ cross-fetch@2.2.2: node-fetch "2.1.2" whatwg-fetch "2.0.4" +cross-fetch@3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.0.4.tgz#7bef7020207e684a7638ef5f2f698e24d9eb283c" + integrity sha512-MSHgpjQqgbT/94D4CyADeNoYh52zMkCX4pcJvPP5WqPsLFMKjr2TCMg381ox5qI0ii2dPwaLx/00477knXqXVw== + dependencies: + node-fetch "2.6.0" + whatwg-fetch "3.0.0" + cross-spawn-async@^2.1.1: version "2.2.5" resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc" @@ -11034,6 +11624,11 @@ dateformat@^3.0.2: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== +de-indent@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" + integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0= + debug-fabulous@1.X: version "1.1.0" resolved "https://registry.yarnpkg.com/debug-fabulous/-/debug-fabulous-1.1.0.tgz#af8a08632465224ef4174a9f06308c3c2a1ebc8e" @@ -11229,7 +11824,7 @@ deep-object-diff@^1.1.0: resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a" integrity sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw== -deepmerge@3.2.0, deepmerge@^4.0.0, deepmerge@^4.2.2: +deepmerge@3.2.0, deepmerge@4.2.2, deepmerge@^4.0.0, deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== @@ -11389,6 +11984,11 @@ depd@~1.1.1, depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= +dependency-graph@0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.8.1.tgz#9b8cae3aa2c7bd95ccb3347a09a2d1047a6c3c5a" + integrity sha512-g213uqF8fyk40W8SBjm079n3CZB4qSpCrA2ye1fLGzH/4HEgB6tzuW2CbLE7leb4t45/6h44Ud59Su1/ROTfqw== + dependency-tree@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/dependency-tree/-/dependency-tree-7.0.2.tgz#01df8bbdc51e41438f5bb93f4a53e1a9cf8301a1" @@ -11819,6 +12419,14 @@ dot-case@^2.1.0: dependencies: no-case "^2.2.0" +dot-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.3.tgz#21d3b52efaaba2ea5fda875bb1aa8124521cf4aa" + integrity sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA== + dependencies: + no-case "^3.0.3" + tslib "^1.10.0" + dot-prop@^4.1.0, dot-prop@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" @@ -13429,20 +14037,6 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" -extglob@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.3.tgz#55e019d0c95bf873949c737b7e5172dba84ebb29" - integrity sha512-AyptZexgu7qppEPq59DtN/XJGZDrLcVxSHai+4hdgMMS9EpF4GBvygcWWApno8lL9qSjVpYt7Raao28qzJX1ww== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" @@ -13545,38 +14139,15 @@ fast-equals@^2.0.0: resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-2.0.0.tgz#bef2c423af3939f2c54310df54c57e64cd2adefc" integrity sha512-u6RBd8cSiLLxAiC04wVsLV6GBFDOXcTCgWkd3wEoFXgidPSoAJENqC9m7Jb2vewSvjBIfXV6icKeh3GTKfIaXA== -fast-glob@2.2.7, fast-glob@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" - integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - -fast-glob@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.0.4.tgz#a4b9f49e36175f5ef1a3456f580226a6e7abcc9e" - integrity sha512-JAh0y6ScChRmATdQIsN416LK+bAFiGczD9A4zWBMPcTgkpj9SEOC7DEzpfbqoDKzieZw40dIAKx3PofGxukFqw== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - glob-parent "3.1.0" - merge2 "1.2.1" - micromatch "3.1.5" - -fast-glob@^3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.0.4.tgz#d484a41005cb6faeb399b951fd1bd70ddaebb602" - integrity sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg== +fast-glob@2.2.7, fast-glob@3.1.1, fast-glob@^2.0.2, fast-glob@^2.2.2, fast-glob@^2.2.6, fast-glob@^3.0.3, fast-glob@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.1.1.tgz#87ee30e9e9f3eb40d6f254a7997655da753d7c82" + integrity sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g== dependencies: - "@nodelib/fs.stat" "^2.0.1" - "@nodelib/fs.walk" "^1.2.1" - glob-parent "^5.0.0" - is-glob "^4.0.1" - merge2 "^1.2.3" + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" micromatch "^4.0.2" fast-json-stable-stringify@^2.0.0: @@ -13654,6 +14225,11 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" +fbjs-css-vars@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" + integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== + fbjs@^0.8.0, fbjs@^0.8.1, fbjs@^0.8.16: version "0.8.17" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" @@ -13680,6 +14256,20 @@ fbjs@^0.8.4, fbjs@^0.8.9: setimmediate "^1.0.5" ua-parser-js "^0.7.9" +fbjs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-1.0.0.tgz#52c215e0883a3c86af2a7a776ed51525ae8e0a5a" + integrity sha512-MUgcMEJaFhCaF1QtWGnmq9ZDRAzECTCRAF7O6UZIlAlkTs1SasiX9aP0Iw7wfD2mJ7wDTNfg2w7u5fSCwJk1OA== + dependencies: + core-js "^2.4.1" + fbjs-css-vars "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + fd-slicer@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" @@ -14450,7 +15040,17 @@ fsevents@~2.1.0: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.0.tgz#ce1a5f9ac71c6d75278b0c5bd236d7dfece4cbaa" integrity sha512-+iXhW3LuDQsno8dOIrCIT/CBjeBWuP7PXe8w9shnj9Lebny/Gx1ZjVBYwexLz36Ri2jKuXMNpV6CYNh8lHHgrQ== -fstream@^1.0.0, fstream@^1.0.12: +fstream@^1.0.0: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +fstream@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== @@ -14804,7 +15404,7 @@ glob-all@^3.1.0: glob "^7.0.5" yargs "~1.2.6" -glob-parent@3.1.0, glob-parent@^3.1.0: +glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= @@ -14819,7 +15419,7 @@ glob-parent@^5.0.0: dependencies: is-glob "^4.0.1" -glob-parent@~5.1.0: +glob-parent@^5.1.0, glob-parent@~5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== @@ -14842,11 +15442,6 @@ glob-stream@^6.1.0: to-absolute-glob "^2.0.0" unique-stream "^2.0.2" -glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= - glob-to-regexp@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.0.tgz#49bd677b1671022bd10921c3788f23cdebf9c7e6" @@ -15025,6 +15620,18 @@ globals@^9.18.0, globals@^9.2.0: resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== +globby@11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.0.tgz#56fd0e9f0d4f8fb0c456f1ab0dee96e1380bc154" + integrity sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globby@8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d" @@ -15307,11 +15914,13 @@ graphlib@^2.1.7: lodash "^4.17.5" graphql-anywhere@^4.1.0-alpha.0: - version "4.1.16" - resolved "https://registry.yarnpkg.com/graphql-anywhere/-/graphql-anywhere-4.1.16.tgz#82bb59643e30183cfb7b485ed4262a7b39d8a6c1" - integrity sha512-DNQGxrh2p8w4vQwHIW1Sw65ZDbOr6ktQCeol6itH3LeWy1a3IoZ67jxrhgrHM+Upg8oiazvteSr64VRxJ8n5+g== + version "4.2.4" + resolved "https://registry.yarnpkg.com/graphql-anywhere/-/graphql-anywhere-4.2.4.tgz#7f1c08c9348c730c6bb5e818c81f0b72c13696a8" + integrity sha512-rN6Op5vle0Ucqo8uOVPuFzRz1L/MB+ZVa+XezhFcQ6iP13vy95HOXRysrRtWcu2kQQTLyukSGmfU08D8LXWSIw== dependencies: - apollo-utilities "^1.0.18" + apollo-utilities "^1.3.2" + ts-invariant "^0.3.2" + tslib "^1.9.3" graphql-code-generator@^0.18.2: version "0.18.2" @@ -15440,9 +16049,9 @@ graphql-extensions@^0.0.x, graphql-extensions@~0.0.9: source-map-support "^0.5.1" graphql-fields@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/graphql-fields/-/graphql-fields-1.2.1.tgz#3777112af0bd6f55cc3c7b8f6d7748ab7a1b23bb" - integrity sha512-ufg/dxb78IjQUblNfiaEMkZWD1CwcZjdK0nTEW0dBQyNArxKZI7N+zohZdIdqVJcihPWJod1yymx4NM+1bZjTw== + version "1.3.0" + resolved "https://registry.yarnpkg.com/graphql-fields/-/graphql-fields-1.3.0.tgz#902ae2fd525eb04ddede7565d447db54dfc56b54" + integrity sha512-juRLzsYgbcJ/YuwExYObDPXn725YyCiVqxx6JlUm4HI5Ytm2RKp6MScaTVieMKtJI+Z6JmNgzInMTNuw0/DbZg== graphql-import@0.7.1, graphql-import@^0.7.1: version "0.7.1" @@ -15470,11 +16079,16 @@ graphql-tag-pluck@0.6.0: source-map-support "^0.5.9" typescript "^3.2.2" -graphql-tag@2.10.1, graphql-tag@^2.9.2: +graphql-tag@2.10.1: version "2.10.1" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.1.tgz#10aa41f1cd8fae5373eaf11f1f67260a3cad5e02" integrity sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg== +graphql-tag@^2.10.2, graphql-tag@^2.10.3: + version "2.10.3" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.3.tgz#ea1baba5eb8fc6339e4c4cf049dabe522b0edf03" + integrity sha512-4FOv3ZKfA4WdOKJeHdz6B3F/vxBLSgmBcGeAFPf4n1F64ltJUvOOerNj0rsJxONQGdhUMynQIvd6LzB+1J5oKA== + graphql-toolkit@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/graphql-toolkit/-/graphql-toolkit-0.2.0.tgz#91364b69911d51bc915269a37963f4ea2d5f335c" @@ -15503,23 +16117,23 @@ graphql-tools@4.0.4: iterall "^1.1.3" uuid "^3.1.0" -graphql-tools@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-3.1.1.tgz#d593358f01e7c8b1671a17b70ddb034dea9dbc50" - integrity sha512-yHvPkweUB0+Q/GWH5wIG60bpt8CTwBklCSzQdEHmRUgAdEQKxw+9B7zB3dG7wB3Ym7M7lfrS4Ej+jtDZfA2UXg== +graphql-tools@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-4.0.6.tgz#0e729e73db05ade3df10a2f92511be544972a844" + integrity sha512-jHLQw8x3xmSNRBCsaZqelXXsFfUSUSktSCUP8KYHiX1Z9qEuwcMpAf+FkdBzk8aTAFqOlPdNZ3OI4DKKqGKUqg== dependencies: - apollo-link "^1.2.2" + apollo-link "^1.2.3" apollo-utilities "^1.0.1" deprecated-decorator "^0.1.6" iterall "^1.1.3" uuid "^3.1.0" -graphql@^0.13.2: - version "0.13.2" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.13.2.tgz#4c740ae3c222823e7004096f832e7b93b2108270" - integrity sha512-QZ5BL8ZO/B20VA8APauGBg3GyEgZ19eduvpLWoq5x7gMmWnHoy8rlQWPLmWgFvo1yNgjSEFMesmS4R6pPr7xog== +graphql@^14.6.0: + version "14.6.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.6.0.tgz#57822297111e874ea12f5cd4419616930cd83e49" + integrity sha512-VKzfvHEKybTKjQVpTFrA5yUq2S9ihcZvfJAtsDBBCuV6wauPu1xl/f9ehgVf0FcEJJs4vz6ysb/ZMkGigQZseg== dependencies: - iterall "^1.2.1" + iterall "^1.2.2" graphviz@^0.0.8: version "0.0.8" @@ -16068,7 +16682,7 @@ hawk@~6.0.2: hoek "4.x.x" sntp "2.x.x" -he@1.2.0, he@1.2.x, he@^1.1.1: +he@1.2.0, he@1.2.x, he@^1.1.0, he@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== @@ -16572,6 +17186,11 @@ ignore@^5.1.1: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.2.tgz#e28e584d43ad7e92f96995019cc43b9e1ac49558" integrity sha512-vdqWBp7MyzdmHkkRWV5nY+PfGRbYbahfuvsBCh277tq+w9zyNi7h5CYJCK0kmzti9kU+O/cB7sE8HvKv6aXAKQ== +ignore@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" + integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== + image-size@~0.5.0: version "0.5.5" resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" @@ -16597,6 +17216,11 @@ immutable@^4.0.0-rc.9: resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.12.tgz#ca59a7e4c19ae8d9bf74a97bdf0f6e2f2a5d0217" integrity sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A== +immutable@~3.7.6: + version "3.7.6" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" + integrity sha1-E7TTyxK++hVIKib+Gy665kAHHks= + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -16627,6 +17251,13 @@ import-from@2.1.0, import-from@^2.1.0: dependencies: resolve-from "^3.0.0" +import-from@3.0.0, import-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-3.0.0.tgz#055cfec38cd5a27d8057ca51376d7d3bf0891966" + integrity sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ== + dependencies: + resolve-from "^5.0.0" + import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" @@ -17312,6 +17943,13 @@ is-glob@4.0.0, is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" +is-glob@4.0.1, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + is-glob@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -17326,13 +17964,6 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - is-hexadecimal@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.1.tgz#6e084bbc92061fbb0971ec58b6ce6d404e24da69" @@ -17455,13 +18086,6 @@ is-observable@^1.1.0: dependencies: symbol-observable "^1.1.0" -is-odd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-1.0.0.tgz#3b8a932eb028b3775c39bb09e91767accdb69088" - integrity sha1-O4qTLrAos3dcObsJ6RdnrM22kIg= - dependencies: - is-number "^3.0.0" - is-odd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" @@ -17948,7 +18572,7 @@ items@2.x.x: resolved "https://registry.yarnpkg.com/items/-/items-2.1.1.tgz#8bd16d9c83b19529de5aea321acaada78364a198" integrity sha1-i9FtnIOxlSneWuoyGsqtp4NkoZg= -iterall@^1.1.3, iterall@^1.2.1: +iterall@^1.1.3, iterall@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7" integrity sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA== @@ -19769,7 +20393,12 @@ lodash.uniqby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= -lodash@4.17.11, lodash@4.17.15, lodash@>4.17.4, lodash@^4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.10.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.1, lodash@~4.17.10, lodash@~4.17.15, lodash@~4.17.5: +lodash@4.17.11: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + +lodash@4.17.15, lodash@>4.17.4, lodash@^4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.10.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.1, lodash@~4.17.10, lodash@~4.17.15, lodash@~4.17.5: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -19909,6 +20538,13 @@ lower-case-first@^1.0.0: dependencies: lower-case "^1.1.2" +lower-case@2.0.1, lower-case@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.1.tgz#39eeb36e396115cc05e29422eaea9e692c9408c7" + integrity sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ== + dependencies: + tslib "^1.10.0" + lower-case@^1.1.0, lower-case@^1.1.1, lower-case@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" @@ -20417,16 +21053,16 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.1.tgz#271d2516ff52d4af7f7b710b8bf3e16e183fef66" - integrity sha512-wUqcG5pxrAcaFI1lkqkMnk3Q7nUxV/NWfpAFSeWUwG9TRODnBDCUHa75mi3o3vLWQ5N4CQERWCauSlP0I3ZqUg== - merge2@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5" integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA== +merge2@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" + integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== + merge@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" @@ -20461,25 +21097,6 @@ micromatch@3.1.10, micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.5.tgz#d05e168c206472dfbca985bfef4f57797b4cd4ba" - integrity sha512-ykttrLPQrz1PUJcXjwsTUjGoPJ64StIGNE2lGVD1c9CuguJ+L7/navsE8IcDNndOoCMvYV0qc/exfVbMHkUhvA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.0" - define-property "^1.0.0" - extend-shallow "^2.0.1" - extglob "^2.0.2" - fragment-cache "^0.2.1" - kind-of "^6.0.0" - nanomatch "^1.2.5" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - micromatch@^4.0.0, micromatch@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" @@ -21110,23 +21727,6 @@ nano-time@1.0.0: dependencies: big-integer "^1.6.16" -nanomatch@^1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.7.tgz#53cd4aa109ff68b7f869591fdc9d10daeeea3e79" - integrity sha512-/5ldsnyurvEw7wNpxLFgjVvBLMta43niEYOy0CJ4ntcYSbx6bugRUTQeFb4BR/WanEL1o3aQgHuVLHQaB6tOqg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^1.0.0" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - is-odd "^1.0.0" - kind-of "^5.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - nanomatch@^1.2.9: version "1.2.9" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" @@ -21278,6 +21878,14 @@ no-case@^2.2.0, no-case@^2.3.2: dependencies: lower-case "^1.1.1" +no-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.3.tgz#c21b434c1ffe48b39087e86cfb4d2582e9df18f8" + integrity sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw== + dependencies: + lower-case "^2.0.1" + tslib "^1.10.0" + nock@10.0.6: version "10.0.6" resolved "https://registry.yarnpkg.com/nock/-/nock-10.0.6.tgz#e6d90ee7a68b8cfc2ab7f6127e7d99aa7d13d111" @@ -21321,16 +21929,16 @@ node-fetch@2.1.2: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5" integrity sha1-q4hOjn5X44qUR1POxwb3iNF2i7U= +node-fetch@2.6.0, node-fetch@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" + integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + node-fetch@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA== -node-fetch@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" - integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== - node-forge@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" @@ -21730,6 +22338,11 @@ null-loader@^3.0.0: loader-utils "^1.2.3" schema-utils "^1.0.0" +nullthrows@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" + integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== + num2fraction@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" @@ -22107,10 +22720,17 @@ oppsy@2.x.x, oppsy@^2.0.0: dependencies: hoek "5.x.x" +optimism@^0.11.5: + version "0.11.5" + resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.11.5.tgz#4c5d45fa0fa1cc9dcf092729b5d6d661b53ff5c9" + integrity sha512-twCHmBb64DYzEZ8A3O+TLCuF/RmZPBhXPQYv4agoiALRLlW9SidMzd7lwUP9mL0jOZhzhnBmb8ajqA00ECo/7g== + dependencies: + "@wry/context" "^0.5.0" + optimism@^0.9.0: - version "0.9.5" - resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.9.5.tgz#b8b5dc9150e97b79ddbf2d2c6c0e44de4d255527" - integrity sha512-lNvmuBgONAGrUbj/xpH69FjMOz1d0jvMNoOCKyVynUPzq2jgVlGL4jFYJqrUHzUfBv+jAFSCP61x5UkfbduYJA== + version "0.9.6" + resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.9.6.tgz#5621195486b294c3bfc518d17ac47767234b029f" + integrity sha512-bWr/ZP32UgFCQAoSkz33XctHwpq2via2sBvGvO5JIlrU8gaiM0LvoKj3QMle9LWdSKlzKik8XGSerzsdfYLNxA== dependencies: "@wry/context" "^0.4.0" @@ -22534,6 +23154,14 @@ param-case@2.1.x, param-case@^2.1.0: dependencies: no-case "^2.2.0" +param-case@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.3.tgz#4be41f8399eff621c56eebb829a5e451d9801238" + integrity sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA== + dependencies: + dot-case "^3.0.3" + tslib "^1.10.0" + parent-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.0.tgz#df250bdc5391f4a085fb589dad761f5ad6b865b5" @@ -22736,6 +23364,14 @@ parseurl@~1.3.3: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +pascal-case@3.1.1, pascal-case@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.1.tgz#5ac1975133ed619281e88920973d2cd1f279de5f" + integrity sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA== + dependencies: + no-case "^3.0.3" + tslib "^1.10.0" + pascal-case@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-2.0.1.tgz#2d578d3455f660da65eca18ef95b4e0de912761e" @@ -25432,15 +26068,10 @@ regex-regex@^1.0.0: resolved "https://registry.yarnpkg.com/regex-regex/-/regex-regex-1.0.0.tgz#9048a1eaeb870f4d480dabc76fc42cdcc0bc3a72" integrity sha1-kEih6uuHD01IDavHb8Qs3MC8OnI= -regexp-tree@^0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.13.tgz#5b19ab9377edc68bc3679256840bb29afc158d7f" - integrity sha512-hwdV/GQY5F8ReLZWO+W1SRoN5YfpOKY6852+tBFcma72DKBIcHjPRIlIvQN35bCOljuAfP2G2iB0FC/w236mUw== - -regexp-tree@^0.1.6: - version "0.1.10" - resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.10.tgz#d837816a039c7af8a8d64d7a7c3cf6a1d93450bc" - integrity sha512-K1qVSbcedffwuIslMwpe6vGlj+ZXRnGkvjAtFHfDZZZuEdA/h0dxljAPu9vhUo6Rrx2U2AwJ+nSQ6hK+lrP5MQ== +regexp-tree@^0.1.13, regexp-tree@^0.1.6: + version "0.1.17" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.17.tgz#66d914a6ca21f95dd7660ed70a7dad47aeb2246a" + integrity sha512-UnOJjFS/EPZmfISmYx+0PcDtPzyFKTe+cZTS5sM5hifnRUDRxoB1j4DAmGwqzxjwBGlwOkGfb2cDGHtjuEwqoA== regexp.prototype.flags@^1.2.0: version "1.2.0" @@ -25541,6 +26172,36 @@ relative@^3.0.2: dependencies: isobject "^2.0.0" +relay-compiler@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/relay-compiler/-/relay-compiler-8.0.0.tgz#567edebc857db5748142b57a78d197f976b5e3ac" + integrity sha512-JrS3Bv6+6S0KloHmXUyTcrdFRpI3NxWdiVQC146vD5jgay9EM464lyf9bEUsCol3na4JUrad4aQ/r+4wWxG1kw== + dependencies: + "@babel/core" "^7.0.0" + "@babel/generator" "^7.5.0" + "@babel/parser" "^7.0.0" + "@babel/runtime" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + babel-preset-fbjs "^3.3.0" + chalk "^2.4.1" + fast-glob "^2.2.2" + fb-watchman "^2.0.0" + fbjs "^1.0.0" + immutable "~3.7.6" + nullthrows "^1.1.1" + relay-runtime "8.0.0" + signedsource "^1.0.0" + yargs "^14.2.0" + +relay-runtime@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/relay-runtime/-/relay-runtime-8.0.0.tgz#52585a7bf04a710bd1bc664bfb0a60dbff3ce6e1" + integrity sha512-lOaZ7K/weTuCIt3pWHkxUG8s7iohI4IyYj65YV4sB9iX6W0uMvt626BFJ4GvNXFmd+OrgNnXcvx1mqRFqJaV8A== + dependencies: + "@babel/runtime" "^7.0.0" + fbjs "^1.0.0" + release-zalgo@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730" @@ -25937,6 +26598,11 @@ resolve-dir@^1.0.0, resolve-dir@^1.0.1: expand-tilde "^2.0.0" global-modules "^1.0.0" +resolve-from@5.0.0, resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" @@ -25952,11 +26618,6 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - resolve-options@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131" @@ -26994,6 +27655,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +signedsource@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/signedsource/-/signedsource-1.0.0.tgz#1ddace4981798f93bd833973803d80d52e93ad6a" + integrity sha1-HdrOSYF5j5O9gzlzgD2A1S6TrWo= + simple-git@1.116.0: version "1.116.0" resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.116.0.tgz#ea6e533466f1e0152186e306e004d4eefa6e3e00" @@ -29228,13 +29894,6 @@ ts-easing@^0.2.0: resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec" integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ== -ts-invariant@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.2.1.tgz#3d587f9d6e3bded97bf9ec17951dd9814d5a9d3f" - integrity sha512-Z/JSxzVmhTo50I+LKagEISFJW3pvPCqsMWLamCTX8Kr3N5aMrnGOqcflbe5hLUzwjvgPfnLzQtHZv0yWQ+FIHg== - dependencies: - tslib "^1.9.3" - ts-invariant@^0.3.2: version "0.3.3" resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.3.3.tgz#b5742b1885ecf9e29c31a750307480f045ec0b16" @@ -29249,6 +29908,13 @@ ts-invariant@^0.4.0: dependencies: tslib "^1.9.3" +ts-invariant@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.4.4.tgz#97a523518688f93aafad01b0e80eb803eb2abd86" + integrity sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA== + dependencies: + tslib "^1.9.3" + ts-loader@^6.0.4: version "6.0.4" resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.0.4.tgz#bc331ad91a887a60632d94c9f79448666f2c4b63" @@ -29283,7 +29949,7 @@ tsd@^0.7.4: typescript "^3.0.1" update-notifier "^2.5.0" -tslib@^1, tslib@^1.10.0: +tslib@1.10.0, tslib@^1, tslib@^1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== @@ -30173,6 +30839,13 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +unixify@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unixify/-/unixify-1.0.0.tgz#3a641c8c2ffbce4da683a5c70f03a462940c2090" + integrity sha1-OmQcjC/7zk2mg6XHDwOkYpQMIJA= + dependencies: + normalize-path "^2.1.1" + unlazy-loader@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/unlazy-loader/-/unlazy-loader-0.1.3.tgz#2efdf05c489da311055586bf3cfca0c541dd8fa5" @@ -30301,6 +30974,13 @@ upper-case-first@^1.1.0, upper-case-first@^1.1.2: dependencies: upper-case "^1.1.1" +upper-case@2.0.1, upper-case@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-2.0.1.tgz#6214d05e235dc817822464ccbae85822b3d8665f" + integrity sha512-laAsbea9SY5osxrv7S99vH9xAaJKrw5Qpdh4ENRLcaxipjKsiaBwiAsxfa8X5mObKNTQPsupSq0J/VIxsSJe3A== + dependencies: + tslib "^1.10.0" + upper-case@^1.0.3, upper-case@^1.1.0, upper-case@^1.1.1, upper-case@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" @@ -31184,6 +31864,14 @@ vt-pbf@^3.1.1: "@mapbox/vector-tile" "^1.3.1" pbf "^3.0.5" +vue-template-compiler@^2.6.11: + version "2.6.11" + resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.11.tgz#c04704ef8f498b153130018993e56309d4698080" + integrity sha512-KIq15bvQDrcCjpGjrAhx4mUlyyHfdmTaoNfeoATHLAiWB+MU3cx4lOzMwrnUh9cCxy0Lt1T11hAFY6TQgroUAA== + dependencies: + de-indent "^1.0.2" + he "^1.1.0" + w3c-hr-time@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" @@ -31494,7 +32182,7 @@ whatwg-fetch@2.0.4: resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== -whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0: +whatwg-fetch@3.0.0, whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== @@ -32455,21 +33143,6 @@ z-schema@~3.18.3: optionalDependencies: commander "^2.7.1" -zen-observable-ts@^0.8.10: - version "0.8.10" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.10.tgz#18e2ce1c89fe026e9621fd83cc05168228fce829" - integrity sha512-5vqMtRggU/2GhePC9OU4sYEWOdvmayp2k3gjPf4F0mXwB3CSbbNznfDUvDJx9O2ZTa1EIXdJhPchQveFKwNXPQ== - dependencies: - zen-observable "^0.8.0" - -zen-observable-ts@^0.8.18: - version "0.8.18" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.18.tgz#ade44b1060cc4a800627856ec10b9c67f5f639c8" - integrity sha512-q7d05s75Rn1j39U5Oapg3HI2wzriVwERVo4N7uFGpIYuHB9ff02P/E92P9B8T7QVC93jCMHpbXH7X0eVR5LA7A== - dependencies: - tslib "^1.9.3" - zen-observable "^0.8.0" - zen-observable-ts@^0.8.20: version "0.8.20" resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.20.tgz#44091e335d3fcbc97f6497e63e7f57d5b516b163" @@ -32483,6 +33156,11 @@ zen-observable@^0.8.0: resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.8.tgz#1ea93995bf098754a58215a1e0a7309e5749ec42" integrity sha512-HnhhyNnwTFzS48nihkCZIJGsWGFcYUz+XPDlPK5W84Ifji8SksC6m7sQWOf8zdCGhzQ4tDYuMYGu5B0N1dXTtg== +zen-observable@^0.8.14: + version "0.8.15" + resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== + zip-stream@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.2.tgz#841efd23214b602ff49c497cba1a85d8b5fbc39c" From a0ffce715ad83d776853843afd058ae2ded7ba3e Mon Sep 17 00:00:00 2001 From: Liza Katz Date: Thu, 27 Feb 2020 08:58:28 +0000 Subject: [PATCH 121/123] Fix plugin path (#58649) --- packages/kbn-plugin-generator/sao_template/sao.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/kbn-plugin-generator/sao_template/sao.js b/packages/kbn-plugin-generator/sao_template/sao.js index 8e5e106190194..9073ce865a963 100755 --- a/packages/kbn-plugin-generator/sao_template/sao.js +++ b/packages/kbn-plugin-generator/sao_template/sao.js @@ -135,8 +135,11 @@ module.exports = function({ name, targetPath }) { 'eslintrc.js': '.eslintrc.js', 'i18nrc.json': '.i18nrc.json', }, - data: answers => - Object.assign( + data: answers => { + const pathToPlugin = answers.customPath + ? resolve(answers.customPath, camelCase(name), 'public') + : resolve(targetPath, 'public'); + return Object.assign( { templateVersion: pkg.version, startCase, @@ -150,13 +153,11 @@ module.exports = function({ name, targetPath }) { hasUi: !!answers.generateApp, hasServer: !!answers.generateApi, hasScss: !!answers.generateScss, - relRoot: relative( - resolve(answers.customPath || targetPath, name, 'public'), - process.cwd() - ), + relRoot: relative(pathToPlugin, process.cwd()), }, answers - ), + ); + }, enforceNewFolder: true, installDependencies: false, async post({ log, answers }) { From 0ef17ca0af9854473fac78b20b7152b5173a3f20 Mon Sep 17 00:00:00 2001 From: ChanghunKang Date: Thu, 27 Feb 2020 19:03:35 +0900 Subject: [PATCH 122/123] [APM] Change naming for pods to "Kubernetes pods". (#54446) (#54538) --- .../apm/server/lib/ui_filters/local_ui_filters/config.ts | 2 +- x-pack/plugins/translations/translations/zh-CN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts index 6363b996ce5bb..06e701e9928f6 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts @@ -34,7 +34,7 @@ const filtersByName = { }, podName: { title: i18n.translate('xpack.apm.localFilters.titles.podName', { - defaultMessage: 'Pod' + defaultMessage: 'Kubernetes pod' }), fieldName: POD_NAME }, diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 32f648826da84..bae8fef5ff280 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -3747,7 +3747,7 @@ "xpack.apm.localFilters.titles.agentName": "代理名称", "xpack.apm.localFilters.titles.containerId": "容器 ID", "xpack.apm.localFilters.titles.host": "主机", - "xpack.apm.localFilters.titles.podName": "Pod", + "xpack.apm.localFilters.titles.podName": "Kubernetes pod", "xpack.apm.localFilters.titles.transactionResult": "事务结果", "xpack.apm.localFilters.titles.transactionType": "事务类型", "xpack.apm.localFiltersTitle": "筛选", From 2b4a9fd7d7d57723cede7c73e14fc932a4c148fe Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 27 Feb 2020 12:08:08 +0100 Subject: [PATCH 123/123] [State Management] State syncing helpers for query service I (#56128) Before this pr: Discover, Visualise and Dashboard in setup phase create own state containers which watch for pinned filters, time and refresh interval changes. This watching and state comparisons happen for each plugin separately and not only when a specific app is mounted. So we ended up with a bunch of similar synchronous work which happens every time query services state changes. After this pr: Query service exposes observable to watch for changes (state$). Discover, Visualise and Dashboard use this observable for sub url tracking instead of creating its own. --- .../state_containers_examples/common/index.ts | 21 + .../state_containers_examples/kibana.json | 4 +- .../public/plugin.ts | 23 +- .../public/{ => todo}/app.tsx | 0 .../public/{ => todo}/todo.tsx | 6 +- .../public/with_data_services/application.tsx | 49 ++ .../with_data_services/components/app.tsx | 243 +++++++++ .../public/with_data_services/types.ts | 31 ++ .../state_containers_examples/server/index.ts | 28 ++ .../server/plugin.ts | 56 +++ .../server/routes/index.ts | 36 ++ .../state_containers_examples/server/types.ts | 23 + .../state_containers_examples/tsconfig.json | 1 + .../np_ready/dashboard_app_controller.tsx | 31 +- .../public/dashboard/np_ready/legacy_app.js | 6 +- .../kibana/public/dashboard/plugin.ts | 22 +- .../kibana/public/discover/plugin.ts | 17 +- .../kibana/public/visualize/plugin.ts | 17 +- .../new_platform/new_platform.karma_mock.js | 1 + src/plugins/data/public/index.ts | 6 +- src/plugins/data/public/query/mocks.ts | 7 +- .../data/public/query/query_service.ts | 11 + .../data/public/query/state_sync/README.md | 3 + .../state_sync/connect_to_query_state.test.ts | 465 ++++++++++++++++++ .../state_sync/connect_to_query_state.ts | 194 ++++++++ .../create_global_query_observable.ts | 87 ++++ .../data/public/query/state_sync/index.ts | 5 +- .../query/state_sync/sync_app_filters.test.ts | 197 -------- .../query/state_sync/sync_app_filters.ts | 65 --- .../public/query/state_sync/sync_query.ts | 188 ------- ...ry.test.ts => sync_state_with_url.test.ts} | 95 +--- .../query/state_sync/sync_state_with_url.ts | 102 ++++ .../data/public/query/state_sync/types.ts | 38 ++ .../public/query/timefilter/timefilter.ts | 13 + .../timefilter/timefilter_service.mock.ts | 2 + .../query_string_input.test.tsx.snap | 30 ++ .../ui/search_bar/create_search_bar.tsx | 46 +- .../__snapshots__/zeek_details.test.tsx.snap | 5 + 38 files changed, 1581 insertions(+), 593 deletions(-) create mode 100644 examples/state_containers_examples/common/index.ts rename examples/state_containers_examples/public/{ => todo}/app.tsx (100%) rename examples/state_containers_examples/public/{ => todo}/todo.tsx (98%) create mode 100644 examples/state_containers_examples/public/with_data_services/application.tsx create mode 100644 examples/state_containers_examples/public/with_data_services/components/app.tsx create mode 100644 examples/state_containers_examples/public/with_data_services/types.ts create mode 100644 examples/state_containers_examples/server/index.ts create mode 100644 examples/state_containers_examples/server/plugin.ts create mode 100644 examples/state_containers_examples/server/routes/index.ts create mode 100644 examples/state_containers_examples/server/types.ts create mode 100644 src/plugins/data/public/query/state_sync/README.md create mode 100644 src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts create mode 100644 src/plugins/data/public/query/state_sync/connect_to_query_state.ts create mode 100644 src/plugins/data/public/query/state_sync/create_global_query_observable.ts delete mode 100644 src/plugins/data/public/query/state_sync/sync_app_filters.test.ts delete mode 100644 src/plugins/data/public/query/state_sync/sync_app_filters.ts delete mode 100644 src/plugins/data/public/query/state_sync/sync_query.ts rename src/plugins/data/public/query/state_sync/{sync_query.test.ts => sync_state_with_url.test.ts} (63%) create mode 100644 src/plugins/data/public/query/state_sync/sync_state_with_url.ts create mode 100644 src/plugins/data/public/query/state_sync/types.ts diff --git a/examples/state_containers_examples/common/index.ts b/examples/state_containers_examples/common/index.ts new file mode 100644 index 0000000000000..25dc2eacf9c75 --- /dev/null +++ b/examples/state_containers_examples/common/index.ts @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const PLUGIN_ID = 'stateContainersExampleWithDataServices'; +export const PLUGIN_NAME = 'State containers example - with data services'; diff --git a/examples/state_containers_examples/kibana.json b/examples/state_containers_examples/kibana.json index 9114a414a4da3..437e9a4fac63c 100644 --- a/examples/state_containers_examples/kibana.json +++ b/examples/state_containers_examples/kibana.json @@ -3,8 +3,8 @@ "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["state_containers_examples"], - "server": false, + "server": true, "ui": true, - "requiredPlugins": [], + "requiredPlugins": ["navigation", "data"], "optionalPlugins": [] } diff --git a/examples/state_containers_examples/public/plugin.ts b/examples/state_containers_examples/public/plugin.ts index beb7b93dbc5b6..38ebf315789c0 100644 --- a/examples/state_containers_examples/public/plugin.ts +++ b/examples/state_containers_examples/public/plugin.ts @@ -18,14 +18,16 @@ */ import { AppMountParameters, CoreSetup, Plugin } from 'kibana/public'; +import { AppPluginDependencies } from './with_data_services/types'; +import { PLUGIN_ID, PLUGIN_NAME } from '../common'; export class StateContainersExamplesPlugin implements Plugin { public setup(core: CoreSetup) { core.application.register({ - id: 'state-containers-example-browser-history', + id: 'stateContainersExampleBrowserHistory', title: 'State containers example - browser history routing', async mount(params: AppMountParameters) { - const { renderApp, History } = await import('./app'); + const { renderApp, History } = await import('./todo/app'); return renderApp(params, { appInstanceId: '1', appTitle: 'Routing with browser history', @@ -34,10 +36,10 @@ export class StateContainersExamplesPlugin implements Plugin { }, }); core.application.register({ - id: 'state-containers-example-hash-history', + id: 'stateContainersExampleHashHistory', title: 'State containers example - hash history routing', async mount(params: AppMountParameters) { - const { renderApp, History } = await import('./app'); + const { renderApp, History } = await import('./todo/app'); return renderApp(params, { appInstanceId: '2', appTitle: 'Routing with hash history', @@ -45,6 +47,19 @@ export class StateContainersExamplesPlugin implements Plugin { }); }, }); + + core.application.register({ + id: PLUGIN_ID, + title: PLUGIN_NAME, + async mount(params: AppMountParameters) { + // Load application bundle + const { renderApp } = await import('./with_data_services/application'); + // Get start services as specified in kibana.json + const [coreStart, depsStart] = await core.getStartServices(); + // Render the application + return renderApp(coreStart, depsStart as AppPluginDependencies, params); + }, + }); } public start() {} diff --git a/examples/state_containers_examples/public/app.tsx b/examples/state_containers_examples/public/todo/app.tsx similarity index 100% rename from examples/state_containers_examples/public/app.tsx rename to examples/state_containers_examples/public/todo/app.tsx diff --git a/examples/state_containers_examples/public/todo.tsx b/examples/state_containers_examples/public/todo/todo.tsx similarity index 98% rename from examples/state_containers_examples/public/todo.tsx rename to examples/state_containers_examples/public/todo/todo.tsx index 84f64f99d0179..c0617620bde53 100644 --- a/examples/state_containers_examples/public/todo.tsx +++ b/examples/state_containers_examples/public/todo/todo.tsx @@ -42,14 +42,14 @@ import { syncStates, getStateFromKbnUrl, BaseState, -} from '../../../src/plugins/kibana_utils/public'; -import { useUrlTracker } from '../../../src/plugins/kibana_react/public'; +} from '../../../../src/plugins/kibana_utils/public'; +import { useUrlTracker } from '../../../../src/plugins/kibana_react/public'; import { defaultState, pureTransitions, TodoActions, TodoState, -} from '../../../src/plugins/kibana_utils/demos/state_containers/todomvc'; +} from '../../../../src/plugins/kibana_utils/demos/state_containers/todomvc'; interface GlobalState { text: string; diff --git a/examples/state_containers_examples/public/with_data_services/application.tsx b/examples/state_containers_examples/public/with_data_services/application.tsx new file mode 100644 index 0000000000000..1de3cbbc5f988 --- /dev/null +++ b/examples/state_containers_examples/public/with_data_services/application.tsx @@ -0,0 +1,49 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { createBrowserHistory } from 'history'; +import { AppMountParameters, CoreStart } from '../../../../src/core/public'; +import { AppPluginDependencies } from './types'; +import { StateDemoApp } from './components/app'; +import { createKbnUrlStateStorage } from '../../../../src/plugins/kibana_utils/public/'; + +export const renderApp = ( + { notifications, http }: CoreStart, + { navigation, data }: AppPluginDependencies, + { appBasePath, element }: AppMountParameters +) => { + const history = createBrowserHistory({ basename: appBasePath }); + const kbnUrlStateStorage = createKbnUrlStateStorage({ useHash: false, history }); + + ReactDOM.render( + , + element + ); + + return () => ReactDOM.unmountComponentAtNode(element); +}; diff --git a/examples/state_containers_examples/public/with_data_services/components/app.tsx b/examples/state_containers_examples/public/with_data_services/components/app.tsx new file mode 100644 index 0000000000000..c820929d8a61d --- /dev/null +++ b/examples/state_containers_examples/public/with_data_services/components/app.tsx @@ -0,0 +1,243 @@ +/* + * 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, { useEffect, useRef, useState, useCallback } from 'react'; +import { History } from 'history'; +import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; +import { Router } from 'react-router-dom'; + +import { + EuiFieldText, + EuiPage, + EuiPageBody, + EuiPageContent, + EuiPageHeader, + EuiTitle, +} from '@elastic/eui'; + +import { CoreStart } from '../../../../../src/core/public'; +import { NavigationPublicPluginStart } from '../../../../../src/plugins/navigation/public'; +import { + connectToQueryState, + syncQueryStateWithUrl, + DataPublicPluginStart, + IIndexPattern, + QueryState, + Filter, + esFilters, + Query, +} from '../../../../../src/plugins/data/public'; +import { + BaseState, + BaseStateContainer, + createStateContainer, + createStateContainerReactHelpers, + IKbnUrlStateStorage, + ReduxLikeStateContainer, + syncState, +} from '../../../../../src/plugins/kibana_utils/public'; +import { PLUGIN_ID, PLUGIN_NAME } from '../../../common'; + +interface StateDemoAppDeps { + notifications: CoreStart['notifications']; + http: CoreStart['http']; + navigation: NavigationPublicPluginStart; + data: DataPublicPluginStart; + history: History; + kbnUrlStateStorage: IKbnUrlStateStorage; +} + +interface AppState { + name: string; + filters: Filter[]; + query?: Query; +} +const defaultAppState: AppState = { + name: '', + filters: [], +}; +const { + Provider: AppStateContainerProvider, + useState: useAppState, + useContainer: useAppStateContainer, +} = createStateContainerReactHelpers>(); + +const App = ({ + notifications, + http, + navigation, + data, + history, + kbnUrlStateStorage, +}: StateDemoAppDeps) => { + const appStateContainer = useAppStateContainer(); + const appState = useAppState(); + + useGlobalStateSyncing(data.query, kbnUrlStateStorage); + useAppStateSyncing(appStateContainer, data.query, kbnUrlStateStorage); + + const onQuerySubmit = useCallback( + ({ query }) => { + appStateContainer.set({ ...appState, query }); + }, + [appStateContainer, appState] + ); + + const indexPattern = useIndexPattern(data); + if (!indexPattern) + return
No index pattern found. Please create an intex patter before loading...
; + + // Render the application DOM. + // Note that `navigation.ui.TopNavMenu` is a stateful component exported on the `navigation` plugin's start contract. + return ( + + + <> + + + + + +

+ +

+
+
+ + appStateContainer.set({ ...appState, name: e.target.value })} + aria-label="My name" + /> + +
+
+ +
+
+ ); +}; + +export const StateDemoApp = (props: StateDemoAppDeps) => { + const appStateContainer = useCreateStateContainer(defaultAppState); + + return ( + + + + ); +}; + +function useCreateStateContainer( + defaultState: State +): ReduxLikeStateContainer { + const stateContainerRef = useRef | null>(null); + if (!stateContainerRef.current) { + stateContainerRef.current = createStateContainer(defaultState); + } + return stateContainerRef.current; +} + +function useIndexPattern(data: DataPublicPluginStart) { + const [indexPattern, setIndexPattern] = useState(); + useEffect(() => { + const fetchIndexPattern = async () => { + const defaultIndexPattern = await data.indexPatterns.getDefault(); + if (defaultIndexPattern) { + setIndexPattern(defaultIndexPattern); + } + }; + fetchIndexPattern(); + }, [data.indexPatterns]); + + return indexPattern; +} + +function useGlobalStateSyncing( + query: DataPublicPluginStart['query'], + kbnUrlStateStorage: IKbnUrlStateStorage +) { + // setup sync state utils + useEffect(() => { + // sync global filters, time filters, refresh interval from data.query to url '_g' + const { stop } = syncQueryStateWithUrl(query, kbnUrlStateStorage); + return () => { + stop(); + }; + }, [query, kbnUrlStateStorage]); +} + +function useAppStateSyncing( + appStateContainer: BaseStateContainer, + query: DataPublicPluginStart['query'], + kbnUrlStateStorage: IKbnUrlStateStorage +) { + // setup sync state utils + useEffect(() => { + // sync app filters with app state container from data.query to state container + const stopSyncingQueryAppStateWithStateContainer = connectToQueryState( + query, + appStateContainer, + { filters: esFilters.FilterStateStore.APP_STATE } + ); + + // sets up syncing app state container with url + const { start: startSyncingAppStateWithUrl, stop: stopSyncingAppStateWithUrl } = syncState({ + storageKey: '_a', + stateStorage: kbnUrlStateStorage, + stateContainer: { + ...appStateContainer, + // stateSync utils requires explicit handling of default state ("null") + set: state => state && appStateContainer.set(state), + }, + }); + + // merge initial state from app state container and current state in url + const initialAppState: AppState = { + ...appStateContainer.get(), + ...kbnUrlStateStorage.get('_a'), + }; + // trigger state update. actually needed in case some data was in url + appStateContainer.set(initialAppState); + + // set current url to whatever is in app state container + kbnUrlStateStorage.set('_a', initialAppState); + + // finally start syncing state containers with url + startSyncingAppStateWithUrl(); + + return () => { + stopSyncingQueryAppStateWithStateContainer(); + stopSyncingAppStateWithUrl(); + }; + }, [query, kbnUrlStateStorage, appStateContainer]); +} diff --git a/examples/state_containers_examples/public/with_data_services/types.ts b/examples/state_containers_examples/public/with_data_services/types.ts new file mode 100644 index 0000000000000..c63074a7a3810 --- /dev/null +++ b/examples/state_containers_examples/public/with_data_services/types.ts @@ -0,0 +1,31 @@ +/* + * 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 { NavigationPublicPluginStart } from '../../../../src/plugins/navigation/public'; +import { DataPublicPluginStart } from '../../../../src/plugins/data/public'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface StateDemoPublicPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface StateDemoPublicPluginStart {} + +export interface AppPluginDependencies { + data: DataPublicPluginStart; + navigation: NavigationPublicPluginStart; +} diff --git a/examples/state_containers_examples/server/index.ts b/examples/state_containers_examples/server/index.ts new file mode 100644 index 0000000000000..51005d78462a2 --- /dev/null +++ b/examples/state_containers_examples/server/index.ts @@ -0,0 +1,28 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PluginInitializerContext } from '../../../src/core/server'; +import { StateDemoServerPlugin } from './plugin'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new StateDemoServerPlugin(initializerContext); +} + +export { StateDemoServerPlugin as Plugin }; +export * from '../common'; diff --git a/examples/state_containers_examples/server/plugin.ts b/examples/state_containers_examples/server/plugin.ts new file mode 100644 index 0000000000000..1c3fa9bfb290e --- /dev/null +++ b/examples/state_containers_examples/server/plugin.ts @@ -0,0 +1,56 @@ +/* + * 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 { + PluginInitializerContext, + CoreSetup, + CoreStart, + Plugin, + Logger, +} from '../../../src/core/server'; + +import { StateDemoPluginSetup, StateDemoPluginStart } from './types'; +import { defineRoutes } from './routes'; + +export class StateDemoServerPlugin implements Plugin { + private readonly logger: Logger; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup(core: CoreSetup) { + this.logger.debug('State_demo: Ssetup'); + const router = core.http.createRouter(); + + // Register server side APIs + defineRoutes(router); + + return {}; + } + + public start(core: CoreStart) { + this.logger.debug('State_demo: Started'); + return {}; + } + + public stop() {} +} + +export { StateDemoServerPlugin as Plugin }; diff --git a/examples/state_containers_examples/server/routes/index.ts b/examples/state_containers_examples/server/routes/index.ts new file mode 100644 index 0000000000000..f6da48ae62c61 --- /dev/null +++ b/examples/state_containers_examples/server/routes/index.ts @@ -0,0 +1,36 @@ +/* + * 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 { IRouter } from '../../../../src/core/server'; + +export function defineRoutes(router: IRouter) { + router.get( + { + path: '/api/state_demo/example', + validate: false, + }, + async (context, request, response) => { + return response.ok({ + body: { + time: new Date().toISOString(), + }, + }); + } + ); +} diff --git a/examples/state_containers_examples/server/types.ts b/examples/state_containers_examples/server/types.ts new file mode 100644 index 0000000000000..6acfc27bd681b --- /dev/null +++ b/examples/state_containers_examples/server/types.ts @@ -0,0 +1,23 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface StateDemoPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface StateDemoPluginStart {} diff --git a/examples/state_containers_examples/tsconfig.json b/examples/state_containers_examples/tsconfig.json index 091130487791b..3f43072c2aade 100644 --- a/examples/state_containers_examples/tsconfig.json +++ b/examples/state_containers_examples/tsconfig.json @@ -9,6 +9,7 @@ "public/**/*.ts", "public/**/*.tsx", "server/**/*.ts", + "common/**/*.ts", "../../typings/**/*" ], "exclude": [] diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx index 075516d52bab6..84dd73882d134 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx @@ -31,18 +31,18 @@ import { DashboardEmptyScreen, DashboardEmptyScreenProps } from './dashboard_emp import { migrateLegacyQuery, subscribeWithScope } from '../legacy_imports'; import { + connectToQueryState, esFilters, IndexPattern, IndexPatternsContract, Query, SavedQuery, - syncAppFilters, - syncQuery, + syncQueryStateWithUrl, } from '../../../../../../plugins/data/public'; import { + getSavedObjectFinder, SaveResult, showSaveModal, - getSavedObjectFinder, } from '../../../../../../plugins/saved_objects/public'; import { @@ -129,9 +129,9 @@ export class DashboardAppController { // starts syncing `_g` portion of url with query services // note: dashboard_state_manager.ts syncs `_a` portion of url const { - stop: stopSyncingGlobalStateWithUrl, + stop: stopSyncingQueryServiceStateWithUrl, hasInheritedQueryFromUrl: hasInheritedGlobalStateFromUrl, - } = syncQuery(queryService, kbnUrlStateStorage); + } = syncQueryStateWithUrl(queryService, kbnUrlStateStorage); let lastReloadRequestTime = 0; @@ -148,11 +148,20 @@ export class DashboardAppController { history, }); - const stopSyncingAppFilters = syncAppFilters(filterManager, { - set: filters => dashboardStateManager.setFilters(filters), - get: () => dashboardStateManager.appState.filters, - state$: dashboardStateManager.appState$.pipe(map(state => state.filters)), - }); + // sync initial app filters from state to filterManager + filterManager.setAppFilters(_.cloneDeep(dashboardStateManager.appState.filters)); + // setup syncing of app filters between appState and filterManager + const stopSyncingAppFilters = connectToQueryState( + queryService, + { + set: ({ filters }) => dashboardStateManager.setFilters(filters || []), + get: () => ({ filters: dashboardStateManager.appState.filters }), + state$: dashboardStateManager.appState$.pipe(map(state => ({ filters: state.filters }))), + }, + { + filters: esFilters.FilterStateStore.APP_STATE, + } + ); // The hash check is so we only update the time filter on dashboard open, not during // normal cross app navigation. @@ -899,7 +908,7 @@ export class DashboardAppController { $scope.$on('$destroy', () => { updateSubscription.unsubscribe(); - stopSyncingGlobalStateWithUrl(); + stopSyncingQueryServiceStateWithUrl(); stopSyncingAppFilters(); visibleSubscription.unsubscribe(); $scope.timefilterSubscriptions$.unsubscribe(); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/legacy_app.js b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/legacy_app.js index ce9cc85be57b2..35b510894179d 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/legacy_app.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/legacy_app.js @@ -33,7 +33,7 @@ import { } from '../../../../../../plugins/kibana_utils/public'; import { DashboardListing, EMPTY_FILTER } from './listing/dashboard_listing'; import { addHelpMenuToAppChrome } from './help_menu/help_menu_util'; -import { syncQuery } from '../../../../../../plugins/data/public'; +import { syncQueryStateWithUrl } from '../../../../../../plugins/data/public'; export function initDashboardApp(app, deps) { initDashboardAppDirective(app, deps); @@ -98,7 +98,7 @@ export function initDashboardApp(app, deps) { const dashboardConfig = deps.dashboardConfig; // syncs `_g` portion of url with query services - const { stop: stopSyncingGlobalStateWithUrl } = syncQuery( + const { stop: stopSyncingQueryServiceStateWithUrl } = syncQueryStateWithUrl( deps.data.query, kbnUrlStateStorage ); @@ -132,7 +132,7 @@ export function initDashboardApp(app, deps) { $scope.core = deps.core; $scope.$on('$destroy', () => { - stopSyncingGlobalStateWithUrl(); + stopSyncingQueryServiceStateWithUrl(); }); }, resolve: { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts index 7d64ee969212f..9e645b7fb3c5f 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts @@ -18,6 +18,7 @@ */ import { BehaviorSubject } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; import { App, AppMountParameters, @@ -29,7 +30,11 @@ import { } from 'kibana/public'; import { i18n } from '@kbn/i18n'; import { RenderDeps } from './np_ready/application'; -import { DataPublicPluginStart, DataPublicPluginSetup } from '../../../../../plugins/data/public'; +import { + DataPublicPluginStart, + DataPublicPluginSetup, + esFilters, +} from '../../../../../plugins/data/public'; import { IEmbeddableStart } from '../../../../../plugins/embeddable/public'; import { Storage } from '../../../../../plugins/kibana_utils/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; @@ -46,7 +51,6 @@ import { } from '../../../../../plugins/kibana_legacy/public'; import { createSavedDashboardLoader } from './saved_dashboard/saved_dashboards'; import { createKbnUrlTracker } from '../../../../../plugins/kibana_utils/public'; -import { getQueryStateContainer } from '../../../../../plugins/data/public'; export interface DashboardPluginStartDependencies { data: DataPublicPluginStart; @@ -78,9 +82,6 @@ export class DashboardPlugin implements Plugin { constructor(private initializerContext: PluginInitializerContext) {} public setup(core: CoreSetup, { home, kibanaLegacy, data }: DashboardPluginSetupDependencies) { - const { querySyncStateContainer, stop: stopQuerySyncStateContainer } = getQueryStateContainer( - data.query - ); const { appMounted, appUnMounted, stop: stopUrlTracker } = createKbnUrlTracker({ baseUrl: core.http.basePath.prepend('/app/kibana'), defaultSubUrl: `#${DashboardConstants.LANDING_PAGE_PATH}`, @@ -97,12 +98,19 @@ export class DashboardPlugin implements Plugin { stateParams: [ { kbnUrlKey: '_g', - stateUpdate$: querySyncStateContainer.state$, + stateUpdate$: data.query.state$.pipe( + filter( + ({ changes }) => !!(changes.globalFilters || changes.time || changes.refreshInterval) + ), + map(({ state }) => ({ + ...state, + filters: state.filters?.filter(esFilters.isFilterPinned), + })) + ), }, ], }); this.stopUrlTracking = () => { - stopQuerySyncStateContainer(); stopUrlTracker(); }; const app: App = { diff --git a/src/legacy/core_plugins/kibana/public/discover/plugin.ts b/src/legacy/core_plugins/kibana/public/discover/plugin.ts index e8ded9d99f892..3ba0418d35f71 100644 --- a/src/legacy/core_plugins/kibana/public/discover/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/discover/plugin.ts @@ -18,6 +18,7 @@ */ import { BehaviorSubject } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; import { i18n } from '@kbn/i18n'; import { AppMountParameters, CoreSetup, CoreStart, Plugin } from 'kibana/public'; import angular, { auto } from 'angular'; @@ -25,7 +26,7 @@ import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public'; import { DataPublicPluginStart, DataPublicPluginSetup, - getQueryStateContainer, + esFilters, } from '../../../../../plugins/data/public'; import { registerFeature } from './np_ready/register_feature'; import './kibana_services'; @@ -103,9 +104,6 @@ export class DiscoverPlugin implements Plugin { public initializeServices?: () => Promise<{ core: CoreStart; plugins: DiscoverStartPlugins }>; setup(core: CoreSetup, plugins: DiscoverSetupPlugins): DiscoverSetup { - const { querySyncStateContainer, stop: stopQuerySyncStateContainer } = getQueryStateContainer( - plugins.data.query - ); const { appMounted, appUnMounted, stop: stopUrlTracker } = createKbnUrlTracker({ baseUrl: core.http.basePath.prepend('/app/kibana'), defaultSubUrl: '#/discover', @@ -115,12 +113,19 @@ export class DiscoverPlugin implements Plugin { stateParams: [ { kbnUrlKey: '_g', - stateUpdate$: querySyncStateContainer.state$, + stateUpdate$: plugins.data.query.state$.pipe( + filter( + ({ changes }) => !!(changes.globalFilters || changes.time || changes.refreshInterval) + ), + map(({ state }) => ({ + ...state, + filters: state.filters?.filter(esFilters.isFilterPinned), + })) + ), }, ], }); this.stopUrlTracking = () => { - stopQuerySyncStateContainer(); stopUrlTracker(); }; diff --git a/src/legacy/core_plugins/kibana/public/visualize/plugin.ts b/src/legacy/core_plugins/kibana/public/visualize/plugin.ts index 9f2283d29c203..b9e4487ae84fb 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/plugin.ts @@ -19,6 +19,7 @@ import { BehaviorSubject } from 'rxjs'; import { i18n } from '@kbn/i18n'; +import { filter, map } from 'rxjs/operators'; import { AppMountParameters, @@ -33,7 +34,7 @@ import { Storage, createKbnUrlTracker } from '../../../../../plugins/kibana_util import { DataPublicPluginStart, DataPublicPluginSetup, - getQueryStateContainer, + esFilters, } from '../../../../../plugins/data/public'; import { IEmbeddableStart } from '../../../../../plugins/embeddable/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; @@ -85,9 +86,6 @@ export class VisualizePlugin implements Plugin { core: CoreSetup, { home, kibanaLegacy, usageCollection, data }: VisualizePluginSetupDependencies ) { - const { querySyncStateContainer, stop: stopQuerySyncStateContainer } = getQueryStateContainer( - data.query - ); const { appMounted, appUnMounted, stop: stopUrlTracker, setActiveUrl } = createKbnUrlTracker({ baseUrl: core.http.basePath.prepend('/app/kibana'), defaultSubUrl: '#/visualize', @@ -97,12 +95,19 @@ export class VisualizePlugin implements Plugin { stateParams: [ { kbnUrlKey: '_g', - stateUpdate$: querySyncStateContainer.state$, + stateUpdate$: data.query.state$.pipe( + filter( + ({ changes }) => !!(changes.globalFilters || changes.time || changes.refreshInterval) + ), + map(({ state }) => ({ + ...state, + filters: state.filters?.filter(esFilters.isFilterPinned), + })) + ), }, ], }); this.stopUrlTracking = () => { - stopQuerySyncStateContainer(); stopUrlTracker(); }; diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index cf8537ba7ab3e..75f48beb140a2 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -104,6 +104,7 @@ export const npSetup = { getProvider: sinon.fake(), }, query: { + state$: mockObservable(), filterManager: { getFetches$: sinon.fake(), getFilters: sinon.fake(), diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 978f140eb1d26..5dcf51ecc81eb 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -294,11 +294,11 @@ export { Filter, Query, RefreshInterval, TimeRange } from '../common'; export { createSavedQueryService, - syncAppFilters, - syncQuery, + connectToQueryState, + syncQueryStateWithUrl, + QueryState, getTime, getQueryLog, - getQueryStateContainer, FilterManager, SavedQuery, SavedQueryService, diff --git a/src/plugins/data/public/query/mocks.ts b/src/plugins/data/public/query/mocks.ts index 2710dadaa23a3..47b0a5b871ce2 100644 --- a/src/plugins/data/public/query/mocks.ts +++ b/src/plugins/data/public/query/mocks.ts @@ -17,7 +17,8 @@ * under the License. */ -import { QueryService, QuerySetup } from '.'; +import { Observable } from 'rxjs'; +import { QueryService, QuerySetup, QueryStart } from '.'; import { timefilterServiceMock } from './timefilter/timefilter_service.mock'; type QueryServiceClientContract = PublicMethodsOf; @@ -26,16 +27,18 @@ const createSetupContractMock = () => { const setupContract: jest.Mocked = { filterManager: jest.fn() as any, timefilter: timefilterServiceMock.createSetupContract(), + state$: new Observable(), }; return setupContract; }; const createStartContractMock = () => { - const startContract = { + const startContract: jest.Mocked = { filterManager: jest.fn() as any, timefilter: timefilterServiceMock.createStartContract(), savedQueries: jest.fn() as any, + state$: new Observable(), }; return startContract; diff --git a/src/plugins/data/public/query/query_service.ts b/src/plugins/data/public/query/query_service.ts index ebef8b8d45050..c885d596f1943 100644 --- a/src/plugins/data/public/query/query_service.ts +++ b/src/plugins/data/public/query/query_service.ts @@ -17,11 +17,13 @@ * under the License. */ +import { share } from 'rxjs/operators'; import { CoreStart } from 'src/core/public'; import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { FilterManager } from './filter_manager'; import { TimefilterService, TimefilterSetup } from './timefilter'; import { createSavedQueryService } from './saved_query/saved_query_service'; +import { createQueryStateObservable } from './state_sync/create_global_query_observable'; /** * Query Service @@ -36,6 +38,8 @@ export class QueryService { filterManager!: FilterManager; timefilter!: TimefilterSetup; + state$!: ReturnType; + public setup({ uiSettings, storage }: QueryServiceDependencies) { this.filterManager = new FilterManager(uiSettings); @@ -45,9 +49,15 @@ export class QueryService { storage, }); + this.state$ = createQueryStateObservable({ + filterManager: this.filterManager, + timefilter: this.timefilter, + }).pipe(share()); + return { filterManager: this.filterManager, timefilter: this.timefilter, + state$: this.state$, }; } @@ -55,6 +65,7 @@ export class QueryService { return { filterManager: this.filterManager, timefilter: this.timefilter, + state$: this.state$, savedQueries: createSavedQueryService(savedObjects.client), }; } diff --git a/src/plugins/data/public/query/state_sync/README.md b/src/plugins/data/public/query/state_sync/README.md new file mode 100644 index 0000000000000..6b9b158100573 --- /dev/null +++ b/src/plugins/data/public/query/state_sync/README.md @@ -0,0 +1,3 @@ +# Query state syncing utilities + +Set of helpers to connect data services to state containers and state syncing utilities diff --git a/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts b/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts new file mode 100644 index 0000000000000..5da929c441cde --- /dev/null +++ b/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts @@ -0,0 +1,465 @@ +/* + * 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 { Subscription } from 'rxjs'; +import { FilterManager } from '../filter_manager'; +import { getFilter } from '../filter_manager/test_helpers/get_stub_filter'; +import { Filter, FilterStateStore } from '../../../common'; +import { coreMock } from '../../../../../core/public/mocks'; +import { BaseStateContainer, createStateContainer, Storage } from '../../../../kibana_utils/public'; +import { QueryService, QueryStart } from '../query_service'; +import { StubBrowserStorage } from '../../../../../test_utils/public/stub_browser_storage'; +import { connectToQueryState } from './connect_to_query_state'; +import { TimefilterContract } from '../timefilter'; +import { QueryState } from './types'; + +const connectToQueryGlobalState = (query: QueryStart, state: BaseStateContainer) => + connectToQueryState(query, state, { + refreshInterval: true, + time: true, + filters: FilterStateStore.GLOBAL_STATE, + }); + +const connectToQueryAppState = (query: QueryStart, state: BaseStateContainer) => + connectToQueryState(query, state, { + filters: FilterStateStore.APP_STATE, + }); + +const setupMock = coreMock.createSetup(); +const startMock = coreMock.createStart(); + +setupMock.uiSettings.get.mockImplementation((key: string) => { + switch (key) { + case 'filters:pinnedByDefault': + return true; + case 'timepicker:timeDefaults': + return { from: 'now-15m', to: 'now' }; + case 'timepicker:refreshIntervalDefaults': + return { pause: false, value: 0 }; + default: + throw new Error(`sync_query test: not mocked uiSetting: ${key}`); + } +}); + +describe('connect_to_global_state', () => { + let queryServiceStart: QueryStart; + let filterManager: FilterManager; + let timeFilter: TimefilterContract; + let globalState: BaseStateContainer; + let globalStateSub: Subscription; + let globalStateChangeTriggered = jest.fn(); + let filterManagerChangeSub: Subscription; + let filterManagerChangeTriggered = jest.fn(); + + let gF1: Filter; + let gF2: Filter; + let aF1: Filter; + let aF2: Filter; + + beforeEach(() => { + const queryService = new QueryService(); + queryService.setup({ + uiSettings: setupMock.uiSettings, + storage: new Storage(new StubBrowserStorage()), + }); + queryServiceStart = queryService.start(startMock.savedObjects); + filterManager = queryServiceStart.filterManager; + timeFilter = queryServiceStart.timefilter.timefilter; + + globalState = createStateContainer({}); + globalStateChangeTriggered = jest.fn(); + globalStateSub = globalState.state$.subscribe(globalStateChangeTriggered); + + filterManagerChangeTriggered = jest.fn(); + filterManagerChangeSub = filterManager.getUpdates$().subscribe(filterManagerChangeTriggered); + + gF1 = getFilter(FilterStateStore.GLOBAL_STATE, true, true, 'key1', 'value1'); + gF2 = getFilter(FilterStateStore.GLOBAL_STATE, false, false, 'key2', 'value2'); + aF1 = getFilter(FilterStateStore.APP_STATE, true, true, 'key3', 'value3'); + aF2 = getFilter(FilterStateStore.APP_STATE, false, false, 'key4', 'value4'); + }); + afterEach(() => { + globalStateSub.unsubscribe(); + filterManagerChangeSub.unsubscribe(); + }); + + test('state is initialized with state from query service', () => { + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + + expect(globalState.get()).toEqual({ + filters: filterManager.getGlobalFilters(), + refreshInterval: timeFilter.getRefreshInterval(), + time: timeFilter.getTime(), + }); + + stop(); + }); + + test('when time range changes, state container contains updated time range', () => { + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + timeFilter.setTime({ from: 'now-30m', to: 'now' }); + expect(globalState.get().time).toEqual({ + from: 'now-30m', + to: 'now', + }); + stop(); + }); + + test('when refresh interval changes, state container contains updated refresh interval', () => { + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + timeFilter.setRefreshInterval({ pause: true, value: 100 }); + expect(globalState.get().refreshInterval).toEqual({ + pause: true, + value: 100, + }); + stop(); + }); + + test('state changes should propagate to services', () => { + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + globalStateChangeTriggered.mockClear(); + globalState.set({ + ...globalState.get(), + filters: [gF1, gF2], + refreshInterval: { pause: true, value: 100 }, + time: { from: 'now-30m', to: 'now' }, + }); + + expect(globalStateChangeTriggered).toBeCalledTimes(1); + + expect(filterManager.getGlobalFilters()).toHaveLength(2); + expect(timeFilter.getRefreshInterval()).toEqual({ pause: true, value: 100 }); + expect(timeFilter.getTime()).toEqual({ from: 'now-30m', to: 'now' }); + stop(); + }); + + describe('sync from filterManager to global state', () => { + test('should sync global filters to global state when new global filters set to filterManager', () => { + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + + filterManager.setFilters([gF1, aF1]); + + expect(globalState.get().filters).toHaveLength(1); + stop(); + }); + + test('should not sync app filters to global state ', () => { + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + + filterManager.setFilters([aF1, aF2]); + + expect(globalState.get().filters).toHaveLength(0); + stop(); + }); + + test("should not trigger changes when global filters didn't change", () => { + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + globalStateChangeTriggered.mockClear(); + + filterManager.setFilters([gF1, aF1]); + filterManager.setFilters([gF1, aF2]); + + expect(globalStateChangeTriggered).toBeCalledTimes(1); + expect(globalState.get().filters).toHaveLength(1); + + stop(); + }); + + test('should trigger changes when global filters change', () => { + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + globalStateChangeTriggered.mockClear(); + + filterManager.setFilters([gF1, aF1]); + filterManager.setFilters([gF2, aF1]); + + expect(globalStateChangeTriggered).toBeCalledTimes(2); + expect(globalState.get().filters).toHaveLength(1); + + stop(); + }); + + test('resetting filters should sync to global state', () => { + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + + filterManager.setFilters([gF1, aF1]); + + expect(globalState.get().filters).toHaveLength(1); + + filterManager.removeAll(); + + expect(globalState.get().filters).toHaveLength(0); + + stop(); + }); + + test("shouldn't sync filters when syncing is stopped", () => { + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + + filterManager.setFilters([gF1, aF1]); + + expect(globalState.get().filters).toHaveLength(1); + + stop(); + + filterManager.removeAll(); + + expect(globalState.get().filters).toHaveLength(1); + }); + + test('should pick up initial state from filterManager', () => { + globalState.set({ filters: [gF1] }); + filterManager.setFilters([aF1]); + + globalStateChangeTriggered.mockClear(); + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + expect(globalStateChangeTriggered).toBeCalledTimes(1); + expect(globalState.get().filters).toHaveLength(0); + + stop(); + }); + }); + describe('sync from global state to filterManager', () => { + test('changes to global state should be synced to global filters', () => { + filterManager.setFilters([aF1]); + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + globalStateChangeTriggered.mockClear(); + + globalState.set({ ...globalState.get(), filters: [gF1] }); + + expect(filterManager.getFilters()).toHaveLength(2); + expect(filterManager.getAppFilters()).toHaveLength(1); + expect(filterManager.getGlobalFilters()).toHaveLength(1); + expect(globalStateChangeTriggered).toBeCalledTimes(1); + stop(); + }); + + test('app filters should remain untouched', () => { + filterManager.setFilters([gF1, gF2, aF1, aF2]); + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + globalStateChangeTriggered.mockClear(); + + globalState.set({ ...globalState.get(), filters: [] }); + + expect(filterManager.getFilters()).toHaveLength(2); + expect(filterManager.getAppFilters()).toHaveLength(2); + expect(filterManager.getGlobalFilters()).toHaveLength(0); + expect(globalStateChangeTriggered).toBeCalledTimes(1); + stop(); + }); + + test("if filters are not changed, filterManager shouldn't trigger update", () => { + filterManager.setFilters([gF1, gF2, aF1, aF2]); + filterManagerChangeTriggered.mockClear(); + + globalState.set({ ...globalState.get(), filters: [gF1, gF2] }); + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + globalState.set({ ...globalState.get(), filters: [gF1, gF2] }); + + expect(filterManagerChangeTriggered).toBeCalledTimes(0); + stop(); + }); + + test('stop() should stop syncing', () => { + filterManager.setFilters([gF1, gF2, aF1, aF2]); + const stop = connectToQueryGlobalState(queryServiceStart, globalState); + globalState.set({ ...globalState.get(), filters: [] }); + expect(filterManager.getFilters()).toHaveLength(2); + stop(); + globalState.set({ ...globalState.get(), filters: [gF1] }); + expect(filterManager.getFilters()).toHaveLength(2); + }); + }); +}); + +describe('connect_to_app_state', () => { + let queryServiceStart: QueryStart; + let filterManager: FilterManager; + let appState: BaseStateContainer; + let appStateSub: Subscription; + let appStateChangeTriggered = jest.fn(); + let filterManagerChangeSub: Subscription; + let filterManagerChangeTriggered = jest.fn(); + + let gF1: Filter; + let gF2: Filter; + let aF1: Filter; + let aF2: Filter; + + beforeEach(() => { + const queryService = new QueryService(); + queryService.setup({ + uiSettings: setupMock.uiSettings, + storage: new Storage(new StubBrowserStorage()), + }); + queryServiceStart = queryService.start(startMock.savedObjects); + filterManager = queryServiceStart.filterManager; + + appState = createStateContainer({}); + appStateChangeTriggered = jest.fn(); + appStateSub = appState.state$.subscribe(appStateChangeTriggered); + + filterManagerChangeTriggered = jest.fn(); + filterManagerChangeSub = filterManager.getUpdates$().subscribe(filterManagerChangeTriggered); + + gF1 = getFilter(FilterStateStore.GLOBAL_STATE, true, true, 'key1', 'value1'); + gF2 = getFilter(FilterStateStore.GLOBAL_STATE, false, false, 'key2', 'value2'); + aF1 = getFilter(FilterStateStore.APP_STATE, true, true, 'key3', 'value3'); + aF2 = getFilter(FilterStateStore.APP_STATE, false, false, 'key4', 'value4'); + }); + afterEach(() => { + appStateSub.unsubscribe(); + filterManagerChangeSub.unsubscribe(); + }); + + describe('sync from filterManager to app state', () => { + test('should sync app filters to app state when new app filters set to filterManager', () => { + const stop = connectToQueryAppState(queryServiceStart, appState); + + filterManager.setFilters([gF1, aF1]); + + expect(appState.get().filters).toHaveLength(1); + stop(); + }); + + test('should not sync global filters to app state ', () => { + const stop = connectToQueryAppState(queryServiceStart, appState); + + filterManager.setFilters([gF1, gF2]); + + expect(appState.get().filters).toHaveLength(0); + stop(); + }); + + test("should not trigger changes when app filters didn't change", () => { + const stop = connectToQueryAppState(queryServiceStart, appState); + appStateChangeTriggered.mockClear(); + + filterManager.setFilters([gF1, aF1]); + filterManager.setFilters([gF2, aF1]); + + expect(appStateChangeTriggered).toBeCalledTimes(1); + expect(appState.get().filters).toHaveLength(1); + + stop(); + }); + + test('should trigger changes when app filters change', () => { + const stop = connectToQueryAppState(queryServiceStart, appState); + appStateChangeTriggered.mockClear(); + + filterManager.setFilters([gF1, aF1]); + filterManager.setFilters([gF1, aF2]); + + expect(appStateChangeTriggered).toBeCalledTimes(2); + expect(appState.get().filters).toHaveLength(1); + + stop(); + }); + + test('resetting filters should sync to app state', () => { + const stop = connectToQueryAppState(queryServiceStart, appState); + + filterManager.setFilters([gF1, aF1]); + + expect(appState.get().filters).toHaveLength(1); + + filterManager.removeAll(); + + expect(appState.get().filters).toHaveLength(0); + + stop(); + }); + + test("shouldn't sync filters when syncing is stopped", () => { + const stop = connectToQueryAppState(queryServiceStart, appState); + + filterManager.setFilters([gF1, aF1]); + + expect(appState.get().filters).toHaveLength(1); + + stop(); + + filterManager.removeAll(); + + expect(appState.get().filters).toHaveLength(1); + }); + + test('should pick up initial state from filterManager', () => { + appState.set({ filters: [aF1] }); + filterManager.setFilters([gF1]); + + appStateChangeTriggered.mockClear(); + const stop = connectToQueryAppState(queryServiceStart, appState); + expect(appStateChangeTriggered).toBeCalledTimes(1); + expect(appState.get().filters).toHaveLength(0); + + stop(); + }); + }); + describe('sync from app state to filterManager', () => { + test('changes to app state should be synced to app filters', () => { + filterManager.setFilters([gF1]); + const stop = connectToQueryAppState(queryServiceStart, appState); + appStateChangeTriggered.mockClear(); + + appState.set({ filters: [aF1] }); + + expect(filterManager.getFilters()).toHaveLength(2); + expect(filterManager.getAppFilters()).toHaveLength(1); + expect(filterManager.getGlobalFilters()).toHaveLength(1); + expect(appStateChangeTriggered).toBeCalledTimes(1); + stop(); + }); + + test('global filters should remain untouched', () => { + filterManager.setFilters([gF1, gF2, aF1, aF2]); + const stop = connectToQueryAppState(queryServiceStart, appState); + appStateChangeTriggered.mockClear(); + + appState.set({ filters: [] }); + + expect(filterManager.getFilters()).toHaveLength(2); + expect(filterManager.getGlobalFilters()).toHaveLength(2); + expect(appStateChangeTriggered).toBeCalledTimes(1); + stop(); + }); + + test("if filters are not changed, filterManager shouldn't trigger update", () => { + filterManager.setFilters([gF1, gF2, aF1, aF2]); + filterManagerChangeTriggered.mockClear(); + + appState.set({ filters: [aF1, aF2] }); + const stop = connectToQueryAppState(queryServiceStart, appState); + appState.set({ filters: [aF1, aF2] }); + + expect(filterManagerChangeTriggered).toBeCalledTimes(0); + stop(); + }); + + test('stop() should stop syncing', () => { + filterManager.setFilters([gF1, gF2, aF1, aF2]); + const stop = connectToQueryAppState(queryServiceStart, appState); + appState.set({ filters: [] }); + expect(filterManager.getFilters()).toHaveLength(2); + stop(); + appState.set({ filters: [aF1] }); + expect(filterManager.getFilters()).toHaveLength(2); + }); + }); +}); diff --git a/src/plugins/data/public/query/state_sync/connect_to_query_state.ts b/src/plugins/data/public/query/state_sync/connect_to_query_state.ts new file mode 100644 index 0000000000000..a22e66860c765 --- /dev/null +++ b/src/plugins/data/public/query/state_sync/connect_to_query_state.ts @@ -0,0 +1,194 @@ +/* + * 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 { Subscription } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; +import _ from 'lodash'; +import { BaseStateContainer } from '../../../../kibana_utils/public'; +import { COMPARE_ALL_OPTIONS, compareFilters } from '../filter_manager/lib/compare_filters'; +import { QuerySetup, QueryStart } from '../query_service'; +import { QueryState, QueryStateChange } from './types'; +import { FilterStateStore } from '../../../common/es_query/filters'; + +/** + * Helper to setup two-way syncing of global data and a state container + * @param QueryService: either setup or start + * @param stateContainer to use for syncing + */ +export const connectToQueryState = ( + { + timefilter: { timefilter }, + filterManager, + state$, + }: Pick, + stateContainer: BaseStateContainer, + syncConfig: { time?: boolean; refreshInterval?: boolean; filters?: FilterStateStore | boolean } +) => { + const syncKeys: Array = []; + if (syncConfig.time) { + syncKeys.push('time'); + } + if (syncConfig.refreshInterval) { + syncKeys.push('refreshInterval'); + } + if (syncConfig.filters) { + switch (syncConfig.filters) { + case true: + syncKeys.push('filters'); + break; + case FilterStateStore.APP_STATE: + syncKeys.push('appFilters'); + break; + case FilterStateStore.GLOBAL_STATE: + syncKeys.push('globalFilters'); + break; + } + } + + // initial syncing + // TODO: + // data services take precedence, this seems like a good default, + // and apps could anyway set their own value after initialisation, + // but maybe maybe this should be a configurable option? + const initialState: QueryState = { ...stateContainer.get() }; + let initialDirty = false; + if (syncConfig.time && !_.isEqual(initialState.time, timefilter.getTime())) { + initialState.time = timefilter.getTime(); + initialDirty = true; + } + if ( + syncConfig.refreshInterval && + !_.isEqual(initialState.refreshInterval, timefilter.getRefreshInterval()) + ) { + initialState.refreshInterval = timefilter.getRefreshInterval(); + initialDirty = true; + } + + if (syncConfig.filters) { + if (syncConfig.filters === true) { + if ( + !initialState.filters || + !compareFilters(initialState.filters, filterManager.getFilters(), COMPARE_ALL_OPTIONS) + ) { + initialState.filters = filterManager.getFilters(); + initialDirty = true; + } + } else if (syncConfig.filters === FilterStateStore.GLOBAL_STATE) { + if ( + !initialState.filters || + !compareFilters(initialState.filters, filterManager.getGlobalFilters(), COMPARE_ALL_OPTIONS) + ) { + initialState.filters = filterManager.getGlobalFilters(); + initialDirty = true; + } + } else if (syncConfig.filters === FilterStateStore.APP_STATE) { + if ( + !initialState.filters || + !compareFilters(initialState.filters, filterManager.getAppFilters(), COMPARE_ALL_OPTIONS) + ) { + initialState.filters = filterManager.getAppFilters(); + initialDirty = true; + } + } + } + + if (initialDirty) { + stateContainer.set({ ...stateContainer.get(), ...initialState }); + } + + // to ignore own state updates + let updateInProgress = false; + + const subs: Subscription[] = [ + state$ + .pipe( + filter(({ changes, state }) => { + if (updateInProgress) return false; + return syncKeys.some(syncKey => changes[syncKey]); + }), + map(({ changes }) => { + const newState: QueryState = {}; + if (syncConfig.time && changes.time) { + newState.time = timefilter.getTime(); + } + if (syncConfig.refreshInterval && changes.refreshInterval) { + newState.refreshInterval = timefilter.getRefreshInterval(); + } + if (syncConfig.filters) { + if (syncConfig.filters === true && changes.filters) { + newState.filters = filterManager.getFilters(); + } else if ( + syncConfig.filters === FilterStateStore.GLOBAL_STATE && + changes.globalFilters + ) { + newState.filters = filterManager.getGlobalFilters(); + } else if (syncConfig.filters === FilterStateStore.APP_STATE && changes.appFilters) { + newState.filters = filterManager.getAppFilters(); + } + } + return newState; + }) + ) + .subscribe(newState => { + stateContainer.set({ ...stateContainer.get(), ...newState }); + }), + stateContainer.state$.subscribe(state => { + updateInProgress = true; + + // cloneDeep is required because services are mutating passed objects + // and state in state container is frozen + if (syncConfig.time) { + const time = state.time || timefilter.getTimeDefaults(); + if (!_.isEqual(time, timefilter.getTime())) { + timefilter.setTime(_.cloneDeep(time)); + } + } + + if (syncConfig.refreshInterval) { + const refreshInterval = state.refreshInterval || timefilter.getRefreshIntervalDefaults(); + if (!_.isEqual(refreshInterval, timefilter.getRefreshInterval())) { + timefilter.setRefreshInterval(_.cloneDeep(refreshInterval)); + } + } + + if (syncConfig.filters) { + const filters = state.filters || []; + if (syncConfig.filters === true) { + if (!compareFilters(filters, filterManager.getFilters(), COMPARE_ALL_OPTIONS)) { + filterManager.setFilters(_.cloneDeep(filters)); + } + } else if (syncConfig.filters === FilterStateStore.APP_STATE) { + if (!compareFilters(filters, filterManager.getAppFilters(), COMPARE_ALL_OPTIONS)) { + filterManager.setAppFilters(_.cloneDeep(filters)); + } + } else if (syncConfig.filters === FilterStateStore.GLOBAL_STATE) { + if (!compareFilters(filters, filterManager.getGlobalFilters(), COMPARE_ALL_OPTIONS)) { + filterManager.setGlobalFilters(_.cloneDeep(filters)); + } + } + } + + updateInProgress = false; + }), + ]; + + return () => { + subs.forEach(s => s.unsubscribe()); + }; +}; diff --git a/src/plugins/data/public/query/state_sync/create_global_query_observable.ts b/src/plugins/data/public/query/state_sync/create_global_query_observable.ts new file mode 100644 index 0000000000000..d0d97bfaaeb36 --- /dev/null +++ b/src/plugins/data/public/query/state_sync/create_global_query_observable.ts @@ -0,0 +1,87 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Observable, Subscription } from 'rxjs'; +import { map, tap } from 'rxjs/operators'; +import { TimefilterSetup } from '../timefilter'; +import { COMPARE_ALL_OPTIONS, compareFilters, FilterManager } from '../filter_manager'; +import { QueryState, QueryStateChange } from './index'; +import { createStateContainer } from '../../../../kibana_utils/public'; +import { isFilterPinned } from '../../../common/es_query/filters'; + +export function createQueryStateObservable({ + timefilter: { timefilter }, + filterManager, +}: { + timefilter: TimefilterSetup; + filterManager: FilterManager; +}): Observable<{ changes: QueryStateChange; state: QueryState }> { + return new Observable(subscriber => { + const state = createStateContainer({ + time: timefilter.getTime(), + refreshInterval: timefilter.getRefreshInterval(), + filters: filterManager.getFilters(), + }); + + let currentChange: QueryStateChange = {}; + const subs: Subscription[] = [ + timefilter.getTimeUpdate$().subscribe(() => { + currentChange.time = true; + state.set({ ...state.get(), time: timefilter.getTime() }); + }), + timefilter.getRefreshIntervalUpdate$().subscribe(() => { + currentChange.refreshInterval = true; + state.set({ ...state.get(), refreshInterval: timefilter.getRefreshInterval() }); + }), + filterManager.getUpdates$().subscribe(() => { + currentChange.filters = true; + + const { filters } = state.get(); + const globalOld = filters?.filter(f => isFilterPinned(f)); + const appOld = filters?.filter(f => !isFilterPinned(f)); + const globalNew = filterManager.getGlobalFilters(); + const appNew = filterManager.getAppFilters(); + + if (!globalOld || !compareFilters(globalOld, globalNew, COMPARE_ALL_OPTIONS)) { + currentChange.globalFilters = true; + } + + if (!appOld || !compareFilters(appOld, appNew, COMPARE_ALL_OPTIONS)) { + currentChange.appFilters = true; + } + + state.set({ + ...state.get(), + filters: filterManager.getFilters(), + }); + }), + state.state$ + .pipe( + map(newState => ({ state: newState, changes: currentChange })), + tap(() => { + currentChange = {}; + }) + ) + .subscribe(subscriber), + ]; + return () => { + subs.forEach(s => s.unsubscribe()); + }; + }); +} diff --git a/src/plugins/data/public/query/state_sync/index.ts b/src/plugins/data/public/query/state_sync/index.ts index 27e02940765cf..e1a3561e022db 100644 --- a/src/plugins/data/public/query/state_sync/index.ts +++ b/src/plugins/data/public/query/state_sync/index.ts @@ -17,5 +17,6 @@ * under the License. */ -export { syncQuery, getQueryStateContainer } from './sync_query'; -export { syncAppFilters } from './sync_app_filters'; +export { connectToQueryState } from './connect_to_query_state'; +export { syncQueryStateWithUrl } from './sync_state_with_url'; +export { QueryState, QueryStateChange } from './types'; diff --git a/src/plugins/data/public/query/state_sync/sync_app_filters.test.ts b/src/plugins/data/public/query/state_sync/sync_app_filters.test.ts deleted file mode 100644 index e01547b1c0fd8..0000000000000 --- a/src/plugins/data/public/query/state_sync/sync_app_filters.test.ts +++ /dev/null @@ -1,197 +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 { Subscription } from 'rxjs'; -import { FilterManager } from '../filter_manager'; -import { getFilter } from '../filter_manager/test_helpers/get_stub_filter'; -import { Filter, FilterStateStore } from '../../../common'; -import { syncAppFilters } from './sync_app_filters'; -import { coreMock } from '../../../../../core/public/mocks'; -import { BaseStateContainer, createStateContainer } from '../../../../kibana_utils/public'; - -const setupMock = coreMock.createSetup(); - -setupMock.uiSettings.get.mockImplementation((key: string) => { - return true; -}); - -describe('sync_app_filters', () => { - let filterManager: FilterManager; - let appState: BaseStateContainer; - let appStateSub: Subscription; - let appStateChangeTriggered = jest.fn(); - let filterManagerChangeSub: Subscription; - let filterManagerChangeTriggered = jest.fn(); - - let gF1: Filter; - let gF2: Filter; - let aF1: Filter; - let aF2: Filter; - - beforeEach(() => { - filterManager = new FilterManager(setupMock.uiSettings); - appState = createStateContainer([] as Filter[]); - appStateChangeTriggered = jest.fn(); - appStateSub = appState.state$.subscribe(appStateChangeTriggered); - - filterManagerChangeTriggered = jest.fn(); - filterManagerChangeSub = filterManager.getUpdates$().subscribe(filterManagerChangeTriggered); - - gF1 = getFilter(FilterStateStore.GLOBAL_STATE, true, true, 'key1', 'value1'); - gF2 = getFilter(FilterStateStore.GLOBAL_STATE, false, false, 'key2', 'value2'); - aF1 = getFilter(FilterStateStore.APP_STATE, true, true, 'key3', 'value3'); - aF2 = getFilter(FilterStateStore.APP_STATE, false, false, 'key4', 'value4'); - }); - afterEach(() => { - appStateSub.unsubscribe(); - filterManagerChangeSub.unsubscribe(); - }); - - describe('sync from filterManager to app state', () => { - test('should sync app filters to app state when new app filters set to filterManager', () => { - const stop = syncAppFilters(filterManager, appState); - - filterManager.setFilters([gF1, aF1]); - - expect(appState.get()).toHaveLength(1); - stop(); - }); - - test('should not sync global filters to app state ', () => { - const stop = syncAppFilters(filterManager, appState); - - filterManager.setFilters([gF1, gF2]); - - expect(appState.get()).toHaveLength(0); - stop(); - }); - - test("should not trigger changes when app filters didn't change", () => { - const stop = syncAppFilters(filterManager, appState); - - filterManager.setFilters([gF1, aF1]); - - filterManager.setFilters([gF2, aF1]); - - expect(appStateChangeTriggered).toBeCalledTimes(1); - expect(appState.get()).toHaveLength(1); - - stop(); - }); - - test('should trigger changes when app filters change', () => { - const stop = syncAppFilters(filterManager, appState); - - filterManager.setFilters([gF1, aF1]); - filterManager.setFilters([gF1, aF2]); - - expect(appStateChangeTriggered).toBeCalledTimes(2); - expect(appState.get()).toHaveLength(1); - - stop(); - }); - - test('resetting filters should sync to app state', () => { - const stop = syncAppFilters(filterManager, appState); - - filterManager.setFilters([gF1, aF1]); - - expect(appState.get()).toHaveLength(1); - - filterManager.removeAll(); - - expect(appState.get()).toHaveLength(0); - - stop(); - }); - - test("shouldn't sync filters when syncing is stopped", () => { - const stop = syncAppFilters(filterManager, appState); - - filterManager.setFilters([gF1, aF1]); - - expect(appState.get()).toHaveLength(1); - - stop(); - - filterManager.removeAll(); - - expect(appState.get()).toHaveLength(1); - }); - }); - describe('sync from app state to filterManager', () => { - test('should pick up initial state from app state', () => { - appState.set([aF1]); - filterManager.setFilters([gF1]); - - const stop = syncAppFilters(filterManager, appState); - expect(filterManager.getFilters()).toHaveLength(2); - expect(appStateChangeTriggered).toBeCalledTimes(1); - - stop(); - }); - - test('changes to app state should be synced to app filters', () => { - filterManager.setFilters([gF1]); - const stop = syncAppFilters(filterManager, appState); - - appState.set([aF1]); - - expect(filterManager.getFilters()).toHaveLength(2); - expect(filterManager.getAppFilters()).toHaveLength(1); - expect(filterManager.getGlobalFilters()).toHaveLength(1); - expect(appStateChangeTriggered).toBeCalledTimes(1); - stop(); - }); - - test('global filters should remain untouched', () => { - filterManager.setFilters([gF1, gF2, aF1, aF2]); - const stop = syncAppFilters(filterManager, appState); - - appState.set([]); - - expect(filterManager.getFilters()).toHaveLength(2); - expect(filterManager.getGlobalFilters()).toHaveLength(2); - expect(appStateChangeTriggered).toBeCalledTimes(1); - stop(); - }); - - test("if filters are not changed, filterManager shouldn't trigger update", () => { - filterManager.setFilters([gF1, gF2, aF1, aF2]); - filterManagerChangeTriggered.mockClear(); - - appState.set([aF1, aF2]); - const stop = syncAppFilters(filterManager, appState); - appState.set([aF1, aF2]); - - expect(filterManagerChangeTriggered).toBeCalledTimes(0); - stop(); - }); - - test('stop() should stop syncing', () => { - filterManager.setFilters([gF1, gF2, aF1, aF2]); - const stop = syncAppFilters(filterManager, appState); - appState.set([]); - expect(filterManager.getFilters()).toHaveLength(2); - stop(); - appState.set([aF1]); - expect(filterManager.getFilters()).toHaveLength(2); - }); - }); -}); diff --git a/src/plugins/data/public/query/state_sync/sync_app_filters.ts b/src/plugins/data/public/query/state_sync/sync_app_filters.ts deleted file mode 100644 index d9956fcc0f6ae..0000000000000 --- a/src/plugins/data/public/query/state_sync/sync_app_filters.ts +++ /dev/null @@ -1,65 +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 _ from 'lodash'; -import { filter, map } from 'rxjs/operators'; -import { COMPARE_ALL_OPTIONS, compareFilters } from '../filter_manager/lib/compare_filters'; -import { Filter } from '../../../common'; -import { FilterManager } from '../filter_manager'; -import { BaseStateContainer } from '../../../../../plugins/kibana_utils/public'; - -/** - * Helper utility to sync application's state filters, with filter manager - * @param filterManager - * @param appState - */ -export function syncAppFilters( - filterManager: FilterManager, - appState: BaseStateContainer -) { - // make sure initial app filters are picked by filterManager - filterManager.setAppFilters(_.cloneDeep(appState.get())); - - const subs = [ - filterManager - .getUpdates$() - .pipe( - map(() => filterManager.getAppFilters()), - filter( - // continue only if app state filters updated - appFilters => !compareFilters(appFilters, appState.get(), COMPARE_ALL_OPTIONS) - ) - ) - .subscribe(appFilters => { - appState.set(appFilters); - }), - - // if appFilters in dashboardStateManager changed (e.g browser history update), - // sync it to filterManager - appState.state$.subscribe(() => { - if (!compareFilters(appState.get(), filterManager.getAppFilters(), COMPARE_ALL_OPTIONS)) { - filterManager.setAppFilters(_.cloneDeep(appState.get())); - } - }), - ]; - - return () => { - subs.forEach(s => s.unsubscribe()); - }; -} diff --git a/src/plugins/data/public/query/state_sync/sync_query.ts b/src/plugins/data/public/query/state_sync/sync_query.ts deleted file mode 100644 index 373f9aa0a5668..0000000000000 --- a/src/plugins/data/public/query/state_sync/sync_query.ts +++ /dev/null @@ -1,188 +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 { Subscription } from 'rxjs'; -import _ from 'lodash'; -import { filter, map } from 'rxjs/operators'; -import { - createStateContainer, - IKbnUrlStateStorage, - syncState, -} from '../../../../kibana_utils/public'; -import { COMPARE_ALL_OPTIONS, compareFilters } from '../filter_manager/lib/compare_filters'; -import { Filter, RefreshInterval, TimeRange } from '../../../common'; -import { QuerySetup, QueryStart } from '../query_service'; - -const GLOBAL_STATE_STORAGE_KEY = '_g'; - -export interface QuerySyncState { - time?: TimeRange; - refreshInterval?: RefreshInterval; - filters?: Filter[]; -} - -/** - * Helper utility to set up syncing between query services and url's '_g' query param - */ -export const syncQuery = (queryStart: QueryStart, urlStateStorage: IKbnUrlStateStorage) => { - const { - timefilter: { timefilter }, - filterManager, - } = queryStart; - // retrieve current state from `_g` url - const initialStateFromUrl = urlStateStorage.get(GLOBAL_STATE_STORAGE_KEY); - - // remember whether there were info in the URL - const hasInheritedQueryFromUrl = Boolean( - initialStateFromUrl && Object.keys(initialStateFromUrl).length - ); - - const { - querySyncStateContainer, - stop: stopPullQueryState, - initialState, - } = getQueryStateContainer(queryStart, initialStateFromUrl || {}); - - const pushQueryStateSubscription = querySyncStateContainer.state$.subscribe( - ({ time, filters: globalFilters, refreshInterval }) => { - // cloneDeep is required because services are mutating passed objects - // and state in state container is frozen - if (time && !_.isEqual(time, timefilter.getTime())) { - timefilter.setTime(_.cloneDeep(time)); - } - - if (refreshInterval && !_.isEqual(refreshInterval, timefilter.getRefreshInterval())) { - timefilter.setRefreshInterval(_.cloneDeep(refreshInterval)); - } - - if ( - globalFilters && - !compareFilters(globalFilters, filterManager.getGlobalFilters(), COMPARE_ALL_OPTIONS) - ) { - filterManager.setGlobalFilters(_.cloneDeep(globalFilters)); - } - } - ); - - // if there weren't any initial state in url, - // then put _g key into url - if (!initialStateFromUrl) { - urlStateStorage.set(GLOBAL_STATE_STORAGE_KEY, initialState, { - replace: true, - }); - } - - // trigger initial syncing from state container to services if needed - querySyncStateContainer.set(initialState); - - const { start, stop: stopSyncState } = syncState({ - stateStorage: urlStateStorage, - stateContainer: { - ...querySyncStateContainer, - set: state => { - if (state) { - // syncState utils requires to handle incoming "null" value - querySyncStateContainer.set(state); - } - }, - }, - storageKey: GLOBAL_STATE_STORAGE_KEY, - }); - - start(); - return { - stop: () => { - stopSyncState(); - pushQueryStateSubscription.unsubscribe(); - stopPullQueryState(); - }, - hasInheritedQueryFromUrl, - }; -}; - -export const getQueryStateContainer = ( - { timefilter: { timefilter }, filterManager }: QuerySetup, - initialStateOverrides: Partial = {} -) => { - const defaultState: QuerySyncState = { - time: timefilter.getTime(), - refreshInterval: timefilter.getRefreshInterval(), - filters: filterManager.getGlobalFilters(), - }; - - const initialState: QuerySyncState = { - ...defaultState, - ...initialStateOverrides, - }; - - // create state container, which will be used for syncing with syncState() util - const querySyncStateContainer = createStateContainer( - initialState, - { - setTime: (state: QuerySyncState) => (time: TimeRange) => ({ ...state, time }), - setRefreshInterval: (state: QuerySyncState) => (refreshInterval: RefreshInterval) => ({ - ...state, - refreshInterval, - }), - setFilters: (state: QuerySyncState) => (filters: Filter[]) => ({ - ...state, - filters, - }), - }, - { - time: (state: QuerySyncState) => () => state.time, - refreshInterval: (state: QuerySyncState) => () => state.refreshInterval, - filters: (state: QuerySyncState) => () => state.filters, - } - ); - - const subs: Subscription[] = [ - timefilter.getTimeUpdate$().subscribe(() => { - querySyncStateContainer.transitions.setTime(timefilter.getTime()); - }), - timefilter.getRefreshIntervalUpdate$().subscribe(() => { - querySyncStateContainer.transitions.setRefreshInterval(timefilter.getRefreshInterval()); - }), - filterManager - .getUpdates$() - .pipe( - map(() => filterManager.getGlobalFilters()), // we need to track only global filters here - filter(newGlobalFilters => { - // continue only if global filters changed - // and ignore app state filters - const oldGlobalFilters = querySyncStateContainer.get().filters; - return ( - !oldGlobalFilters || - !compareFilters(newGlobalFilters, oldGlobalFilters, COMPARE_ALL_OPTIONS) - ); - }) - ) - .subscribe(newGlobalFilters => { - querySyncStateContainer.transitions.setFilters(newGlobalFilters); - }), - ]; - - return { - querySyncStateContainer, - stop: () => { - subs.forEach(s => s.unsubscribe()); - }, - initialState, - }; -}; diff --git a/src/plugins/data/public/query/state_sync/sync_query.test.ts b/src/plugins/data/public/query/state_sync/sync_state_with_url.test.ts similarity index 63% rename from src/plugins/data/public/query/state_sync/sync_query.test.ts rename to src/plugins/data/public/query/state_sync/sync_state_with_url.test.ts index 1e7db2b9fd22f..50dc35ea955ee 100644 --- a/src/plugins/data/public/query/state_sync/sync_query.test.ts +++ b/src/plugins/data/public/query/state_sync/sync_state_with_url.test.ts @@ -31,7 +31,8 @@ import { import { QueryService, QueryStart } from '../query_service'; import { StubBrowserStorage } from 'test_utils/stub_browser_storage'; import { TimefilterContract } from '../timefilter'; -import { getQueryStateContainer, QuerySyncState, syncQuery } from './sync_query'; +import { syncQueryStateWithUrl } from './sync_state_with_url'; +import { QueryState } from './types'; const setupMock = coreMock.createSetup(); const startMock = coreMock.createStart(); @@ -49,7 +50,7 @@ setupMock.uiSettings.get.mockImplementation((key: string) => { } }); -describe('sync_query', () => { +describe('sync_query_state_with_url', () => { let queryServiceStart: QueryStart; let filterManager: FilterManager; let timefilter: TimefilterContract; @@ -90,7 +91,7 @@ describe('sync_query', () => { }); test('url is actually changed when data in services changes', () => { - const { stop } = syncQuery(queryServiceStart, kbnUrlStateStorage); + const { stop } = syncQueryStateWithUrl(queryServiceStart, kbnUrlStateStorage); filterManager.setFilters([gF, aF]); kbnUrlStateStorage.flush(); // sync force location change expect(history.location.hash).toMatchInlineSnapshot( @@ -100,16 +101,16 @@ describe('sync_query', () => { }); test('when filters change, global filters synced to urlStorage', () => { - const { stop } = syncQuery(queryServiceStart, kbnUrlStateStorage); + const { stop } = syncQueryStateWithUrl(queryServiceStart, kbnUrlStateStorage); filterManager.setFilters([gF, aF]); - expect(kbnUrlStateStorage.get('_g')?.filters).toHaveLength(1); + expect(kbnUrlStateStorage.get('_g')?.filters).toHaveLength(1); stop(); }); test('when time range changes, time synced to urlStorage', () => { - const { stop } = syncQuery(queryServiceStart, kbnUrlStateStorage); + const { stop } = syncQueryStateWithUrl(queryServiceStart, kbnUrlStateStorage); timefilter.setTime({ from: 'now-30m', to: 'now' }); - expect(kbnUrlStateStorage.get('_g')?.time).toEqual({ + expect(kbnUrlStateStorage.get('_g')?.time).toEqual({ from: 'now-30m', to: 'now', }); @@ -117,9 +118,9 @@ describe('sync_query', () => { }); test('when refresh interval changes, refresh interval is synced to urlStorage', () => { - const { stop } = syncQuery(queryServiceStart, kbnUrlStateStorage); + const { stop } = syncQueryStateWithUrl(queryServiceStart, kbnUrlStateStorage); timefilter.setRefreshInterval({ pause: true, value: 100 }); - expect(kbnUrlStateStorage.get('_g')?.refreshInterval).toEqual({ + expect(kbnUrlStateStorage.get('_g')?.refreshInterval).toEqual({ pause: true, value: 100, }); @@ -127,7 +128,7 @@ describe('sync_query', () => { }); test('when url is changed, filters synced back to filterManager', () => { - const { stop } = syncQuery(queryServiceStart, kbnUrlStateStorage); + const { stop } = syncQueryStateWithUrl(queryServiceStart, kbnUrlStateStorage); kbnUrlStateStorage.cancel(); // stop initial syncing pending update history.push(pathWithFilter); expect(filterManager.getGlobalFilters()).toHaveLength(1); @@ -137,14 +138,17 @@ describe('sync_query', () => { test('initial url should be synced with services', () => { history.push(pathWithFilter); - const { stop, hasInheritedQueryFromUrl } = syncQuery(queryServiceStart, kbnUrlStateStorage); + const { stop, hasInheritedQueryFromUrl } = syncQueryStateWithUrl( + queryServiceStart, + kbnUrlStateStorage + ); expect(hasInheritedQueryFromUrl).toBe(true); expect(filterManager.getGlobalFilters()).toHaveLength(1); stop(); }); test("url changes shouldn't trigger services updates if data didn't change", () => { - const { stop } = syncQuery(queryServiceStart, kbnUrlStateStorage); + const { stop } = syncQueryStateWithUrl(queryServiceStart, kbnUrlStateStorage); filterManagerChangeTriggered.mockClear(); history.push(pathWithFilter); @@ -156,76 +160,11 @@ describe('sync_query', () => { }); test("if data didn't change, kbnUrlStateStorage.set shouldn't be called", () => { - const { stop } = syncQuery(queryServiceStart, kbnUrlStateStorage); + const { stop } = syncQueryStateWithUrl(queryServiceStart, kbnUrlStateStorage); filterManager.setFilters([gF, aF]); const spy = jest.spyOn(kbnUrlStateStorage, 'set'); filterManager.setFilters([gF]); // global filters didn't change expect(spy).not.toBeCalled(); stop(); }); - - describe('getQueryStateContainer', () => { - test('state is initialized with state from query service', () => { - const { stop, querySyncStateContainer, initialState } = getQueryStateContainer( - queryServiceStart - ); - expect(querySyncStateContainer.getState()).toMatchInlineSnapshot(` - Object { - "filters": Array [], - "refreshInterval": Object { - "pause": true, - "value": 0, - }, - "time": Object { - "from": "now-15m", - "to": "now", - }, - } - `); - expect(initialState).toEqual(querySyncStateContainer.getState()); - stop(); - }); - - test('state takes initial overrides into account', () => { - const { stop, querySyncStateContainer, initialState } = getQueryStateContainer( - queryServiceStart, - { - time: { from: 'now-99d', to: 'now' }, - } - ); - expect(querySyncStateContainer.getState().time).toEqual({ - from: 'now-99d', - to: 'now', - }); - expect(initialState).toEqual(querySyncStateContainer.getState()); - stop(); - }); - - test('when filters change, state container contains updated global filters', () => { - const { stop, querySyncStateContainer } = getQueryStateContainer(queryServiceStart); - filterManager.setFilters([gF, aF]); - expect(querySyncStateContainer.getState().filters).toHaveLength(1); - stop(); - }); - - test('when time range changes, state container contains updated time range', () => { - const { stop, querySyncStateContainer } = getQueryStateContainer(queryServiceStart); - timefilter.setTime({ from: 'now-30m', to: 'now' }); - expect(querySyncStateContainer.getState().time).toEqual({ - from: 'now-30m', - to: 'now', - }); - stop(); - }); - - test('when refresh interval changes, state container contains updated refresh interval', () => { - const { stop, querySyncStateContainer } = getQueryStateContainer(queryServiceStart); - timefilter.setRefreshInterval({ pause: true, value: 100 }); - expect(querySyncStateContainer.getState().refreshInterval).toEqual({ - pause: true, - value: 100, - }); - stop(); - }); - }); }); diff --git a/src/plugins/data/public/query/state_sync/sync_state_with_url.ts b/src/plugins/data/public/query/state_sync/sync_state_with_url.ts new file mode 100644 index 0000000000000..cd7058b9f8f1c --- /dev/null +++ b/src/plugins/data/public/query/state_sync/sync_state_with_url.ts @@ -0,0 +1,102 @@ +/* + * 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 { + createStateContainer, + IKbnUrlStateStorage, + syncState, +} from '../../../../kibana_utils/public'; +import { QuerySetup, QueryStart } from '../query_service'; +import { connectToQueryState } from './connect_to_query_state'; +import { QueryState } from './types'; +import { FilterStateStore } from '../../../common/es_query/filters'; + +const GLOBAL_STATE_STORAGE_KEY = '_g'; + +/** + * Helper to setup syncing of global data with the URL + * @param QueryService: either setup or start + * @param kbnUrlStateStorage to use for syncing + */ +export const syncQueryStateWithUrl = ( + query: Pick, + kbnUrlStateStorage: IKbnUrlStateStorage +) => { + const { + timefilter: { timefilter }, + filterManager, + } = query; + const defaultState: QueryState = { + time: timefilter.getTime(), + refreshInterval: timefilter.getRefreshInterval(), + filters: filterManager.getGlobalFilters(), + }; + + // retrieve current state from `_g` url + const initialStateFromUrl = kbnUrlStateStorage.get(GLOBAL_STATE_STORAGE_KEY); + + // remember whether there was info in the URL + const hasInheritedQueryFromUrl = Boolean( + initialStateFromUrl && Object.keys(initialStateFromUrl).length + ); + + // prepare initial state, whatever was in URL takes precedences over current state in services + const initialState: QueryState = { + ...defaultState, + ...initialStateFromUrl, + }; + + const globalQueryStateContainer = createStateContainer(initialState); + const stopSyncingWithStateContainer = connectToQueryState(query, globalQueryStateContainer, { + refreshInterval: true, + time: true, + filters: FilterStateStore.GLOBAL_STATE, + }); + + // if there weren't any initial state in url, + // then put _g key into url + if (!initialStateFromUrl) { + kbnUrlStateStorage.set(GLOBAL_STATE_STORAGE_KEY, initialState, { + replace: true, + }); + } + + // trigger initial syncing from state container to services if needed + globalQueryStateContainer.set(initialState); + + const { start, stop: stopSyncingWithUrl } = syncState({ + stateStorage: kbnUrlStateStorage, + stateContainer: { + ...globalQueryStateContainer, + set: state => { + globalQueryStateContainer.set(state || defaultState); + }, + }, + storageKey: GLOBAL_STATE_STORAGE_KEY, + }); + + start(); + return { + stop: () => { + stopSyncingWithStateContainer(); + stopSyncingWithUrl(); + }, + hasInheritedQueryFromUrl, + }; +}; diff --git a/src/plugins/data/public/query/state_sync/types.ts b/src/plugins/data/public/query/state_sync/types.ts new file mode 100644 index 0000000000000..747d4d45fe29b --- /dev/null +++ b/src/plugins/data/public/query/state_sync/types.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 { Filter, RefreshInterval, TimeRange } from '../../../common'; + +/** + * All query state service state + */ +export interface QueryState { + time?: TimeRange; + refreshInterval?: RefreshInterval; + filters?: Filter[]; +} + +type QueryStateChangePartial = { + [P in keyof QueryState]?: boolean; +}; + +export interface QueryStateChange extends QueryStateChangePartial { + appFilters?: boolean; // specifies if app filters change + globalFilters?: boolean; // specifies if global filters change +} diff --git a/src/plugins/data/public/query/timefilter/timefilter.ts b/src/plugins/data/public/query/timefilter/timefilter.ts index 58806a9328b1c..4fbdac47fb3b0 100644 --- a/src/plugins/data/public/query/timefilter/timefilter.ts +++ b/src/plugins/data/public/query/timefilter/timefilter.ts @@ -50,8 +50,13 @@ export class Timefilter { private _autoRefreshIntervalId: number = 0; + private readonly timeDefaults: TimeRange; + private readonly refreshIntervalDefaults: RefreshInterval; + constructor(config: TimefilterConfig, timeHistory: TimeHistoryContract) { this._history = timeHistory; + this.timeDefaults = config.timeDefaults; + this.refreshIntervalDefaults = config.refreshIntervalDefaults; this._time = config.timeDefaults; this.setRefreshInterval(config.refreshIntervalDefaults); } @@ -208,6 +213,14 @@ export class Timefilter { this.enabledUpdated$.next(false); }; + public getTimeDefaults(): TimeRange { + return _.cloneDeep(this.timeDefaults); + } + + public getRefreshIntervalDefaults(): RefreshInterval { + return _.cloneDeep(this.refreshIntervalDefaults); + } + private getForceNow = () => { const forceNow = parseQueryString().forceNow as string; if (!forceNow) { diff --git a/src/plugins/data/public/query/timefilter/timefilter_service.mock.ts b/src/plugins/data/public/query/timefilter/timefilter_service.mock.ts index 80c13464ad98a..7863000b1ace4 100644 --- a/src/plugins/data/public/query/timefilter/timefilter_service.mock.ts +++ b/src/plugins/data/public/query/timefilter/timefilter_service.mock.ts @@ -43,6 +43,8 @@ const createSetupContractMock = () => { getBounds: jest.fn(), calculateBounds: jest.fn(), createFilter: jest.fn(), + getRefreshIntervalDefaults: jest.fn(), + getTimeDefaults: jest.fn(), }; const historyMock: jest.Mocked = { diff --git a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap index b411d27a2a965..58f00ff9ed657 100644 --- a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap +++ b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap @@ -197,6 +197,9 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA "query": Object { "filterManager": [MockFunction], "savedQueries": [MockFunction], + "state$": Observable { + "_isScalar": false, + }, "timefilter": Object { "history": Object { "add": [MockFunction], @@ -215,8 +218,10 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA "getEnabledUpdated$": [MockFunction], "getFetch$": [MockFunction], "getRefreshInterval": [MockFunction], + "getRefreshIntervalDefaults": [MockFunction], "getRefreshIntervalUpdate$": [MockFunction], "getTime": [MockFunction], + "getTimeDefaults": [MockFunction], "getTimeUpdate$": [MockFunction], "isAutoRefreshSelectorEnabled": [MockFunction], "isTimeRangeSelectorEnabled": [MockFunction], @@ -855,6 +860,9 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA "query": Object { "filterManager": [MockFunction], "savedQueries": [MockFunction], + "state$": Observable { + "_isScalar": false, + }, "timefilter": Object { "history": Object { "add": [MockFunction], @@ -873,8 +881,10 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA "getEnabledUpdated$": [MockFunction], "getFetch$": [MockFunction], "getRefreshInterval": [MockFunction], + "getRefreshIntervalDefaults": [MockFunction], "getRefreshIntervalUpdate$": [MockFunction], "getTime": [MockFunction], + "getTimeDefaults": [MockFunction], "getTimeUpdate$": [MockFunction], "isAutoRefreshSelectorEnabled": [MockFunction], "isTimeRangeSelectorEnabled": [MockFunction], @@ -1495,6 +1505,9 @@ exports[`QueryStringInput Should pass the query language to the language switche "query": Object { "filterManager": [MockFunction], "savedQueries": [MockFunction], + "state$": Observable { + "_isScalar": false, + }, "timefilter": Object { "history": Object { "add": [MockFunction], @@ -1513,8 +1526,10 @@ exports[`QueryStringInput Should pass the query language to the language switche "getEnabledUpdated$": [MockFunction], "getFetch$": [MockFunction], "getRefreshInterval": [MockFunction], + "getRefreshIntervalDefaults": [MockFunction], "getRefreshIntervalUpdate$": [MockFunction], "getTime": [MockFunction], + "getTimeDefaults": [MockFunction], "getTimeUpdate$": [MockFunction], "isAutoRefreshSelectorEnabled": [MockFunction], "isTimeRangeSelectorEnabled": [MockFunction], @@ -2150,6 +2165,9 @@ exports[`QueryStringInput Should pass the query language to the language switche "query": Object { "filterManager": [MockFunction], "savedQueries": [MockFunction], + "state$": Observable { + "_isScalar": false, + }, "timefilter": Object { "history": Object { "add": [MockFunction], @@ -2168,8 +2186,10 @@ exports[`QueryStringInput Should pass the query language to the language switche "getEnabledUpdated$": [MockFunction], "getFetch$": [MockFunction], "getRefreshInterval": [MockFunction], + "getRefreshIntervalDefaults": [MockFunction], "getRefreshIntervalUpdate$": [MockFunction], "getTime": [MockFunction], + "getTimeDefaults": [MockFunction], "getTimeUpdate$": [MockFunction], "isAutoRefreshSelectorEnabled": [MockFunction], "isTimeRangeSelectorEnabled": [MockFunction], @@ -2790,6 +2810,9 @@ exports[`QueryStringInput Should render the given query 1`] = ` "query": Object { "filterManager": [MockFunction], "savedQueries": [MockFunction], + "state$": Observable { + "_isScalar": false, + }, "timefilter": Object { "history": Object { "add": [MockFunction], @@ -2808,8 +2831,10 @@ exports[`QueryStringInput Should render the given query 1`] = ` "getEnabledUpdated$": [MockFunction], "getFetch$": [MockFunction], "getRefreshInterval": [MockFunction], + "getRefreshIntervalDefaults": [MockFunction], "getRefreshIntervalUpdate$": [MockFunction], "getTime": [MockFunction], + "getTimeDefaults": [MockFunction], "getTimeUpdate$": [MockFunction], "isAutoRefreshSelectorEnabled": [MockFunction], "isTimeRangeSelectorEnabled": [MockFunction], @@ -3445,6 +3470,9 @@ exports[`QueryStringInput Should render the given query 1`] = ` "query": Object { "filterManager": [MockFunction], "savedQueries": [MockFunction], + "state$": Observable { + "_isScalar": false, + }, "timefilter": Object { "history": Object { "add": [MockFunction], @@ -3463,8 +3491,10 @@ exports[`QueryStringInput Should render the given query 1`] = ` "getEnabledUpdated$": [MockFunction], "getFetch$": [MockFunction], "getRefreshInterval": [MockFunction], + "getRefreshIntervalDefaults": [MockFunction], "getRefreshIntervalUpdate$": [MockFunction], "getTime": [MockFunction], + "getTimeDefaults": [MockFunction], "getTimeUpdate$": [MockFunction], "isAutoRefreshSelectorEnabled": [MockFunction], "isTimeRangeSelectorEnabled": [MockFunction], diff --git a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx index 632385e019e4c..7d65e947c0f04 100644 --- a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx @@ -17,7 +17,7 @@ * under the License. */ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { CoreStart } from 'src/core/public'; import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { KibanaContextProvider } from '../../../../kibana_react/public'; @@ -117,13 +117,28 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps) // App name should come from the core application service. // Until it's available, we'll ask the user to provide it for the pre-wired component. return (props: StatefulSearchBarProps) => { + const { useDefaultBehaviors } = props; // Handle queries - const [query, setQuery] = useState( - props.query || { - query: '', - language: core.uiSettings.get('search:queryLanguage'), + const queryRef = useRef(props.query); + const onQuerySubmitRef = useRef(props.onQuerySubmit); + const defaultQuery = { + query: '', + language: core.uiSettings.get('search:queryLanguage'), + }; + const [query, setQuery] = useState(props.query || defaultQuery); + + useEffect(() => { + if (props.query !== queryRef.current) { + queryRef.current = props.query; + setQuery(props.query || defaultQuery); } - ); + }, [defaultQuery, props.query]); + + useEffect(() => { + if (props.onQuerySubmit !== onQuerySubmitRef.current) { + onQuerySubmitRef.current = props.onQuerySubmit; + } + }, [props.onQuerySubmit]); // handle service state updates. // i.e. filters being added from a visualization directly to filterManager. @@ -150,16 +165,15 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps) // Fire onQuerySubmit on query or timerange change useEffect(() => { - if (!props.useDefaultBehaviors) return; - if (props.onQuerySubmit) - props.onQuerySubmit( - { - dateRange: timeRange, - query, - }, - true - ); - }, [props, props.onQuerySubmit, props.useDefaultBehaviors, query, timeRange]); + if (!useDefaultBehaviors || !onQuerySubmitRef.current) return; + onQuerySubmitRef.current( + { + dateRange: timeRange, + query, + }, + true + ); + }, [query, timeRange, useDefaultBehaviors]); return (